[HN Gopher] A decade of developing a programming language
___________________________________________________________________
A decade of developing a programming language
Author : YorickPeterse
Score : 92 points
Date : 2023-11-14 11:31 UTC (11 hours ago)
(HTM) web link (yorickpeterse.com)
(TXT) w3m dump (yorickpeterse.com)
| otoburb wrote:
| >> _" In reality, gradual typing ends up giving you the worst of
| both dynamic and static typing: you get the uncertainty and lack
| of safety (in dynamically typed contexts) of dynamic typing, and
| the cost of trying to fit your ideas into a statically typed type
| system. I also found that the use of gradual typing didn't
| actually make me more productive compared to using static
| typing."_
|
| The Elixir team didn't get that memo because they are actively in
| the process of researching and working on a gradual type
| implementation.[1]
|
| [1] https://elixir-lang.org/blog/2023/09/20/strong-arrows-
| gradua...
| wk_end wrote:
| Pursuing gradual typing makes sense when you've got an
| established dynamic language and want to incorporate typing
| into it (forget Elixir, let's just look at the massive success
| of TypeScript). But as OP's recommendation says - "for new
| languages", gradual typing has lots of costs and fewer
| benefits.
|
| To put it in other terms: my informal impression is that the
| dynamic "features" of TypeScript are used grudgingly; the
| community strongly pushes towards strictness, eliminating anys,
| preferring well-typed libraries, and so on. There's little
| appetite to - in a single project, unless absolutely required -
| mix-and-match dynamism with staticness, which is the thing that
| gradual typing gets you. Rather, it feels like we're migrating
| from dynamic to static and gradual typing is just how we're
| doing the migration. But in the case of a new language, why not
| just start at the destination?
| mikepurvis wrote:
| I wish Python was further down this path-- I experimented
| with adding annotations and the mypy checker to a bunch of
| code at my company, and it seemed hopeless. Most libraries
| didn't have annotations at all, or there were annotations
| being maintained by a third party in a separate pypi package,
| but the annotations were out of sync with the main project
| and thus blew up in weird ways.
|
| I feel for the people trying to develop these gradual systems
| but it's truly a herculean task, especially in the Python
| community that is now understandably so _extremely_ shy about
| major breaking changes.
| galdor wrote:
| I might be missing something, but the appeal of gradual
| typing to me is that I can mostly type functions, providing
| safe input/output boundaries, and avoid having to type every
| single variable (unless I have to do so for performance
| reasons, as I do in Common Lisp).
|
| This approach is comfortable to me both in Erlang and in
| Common Lisp, I see it as a balance between
| safety/performances and development speed (and I'm saying
| that as someone using Go for all professional development and
| being really happy with its full static typing).
| LegibleCrimson wrote:
| > avoid having to type every single variable
|
| Most static languages don't make you type every single
| variable anymore. Java, C++, Rust, C#, and many others let
| you make the compiler infer types where reasonably
| possible. That's still full static typing.
|
| My Python and Rust have about the same kinds of explicit
| type annotations in roughly the same places. My C++ has a
| little bit more, just because `Foo obj{a}` is more
| idiomatic than `auto foo = Foo{a}`.
| munificent wrote:
| I think the author's recommendation has some needed context:
|
| _> Recommendation: either make your language statically typed
| or dynamically typed (preferably statically typed, but that 's
| a different topic), as gradual typing just doesn't make sense
| for new languages._
|
| The "for new languages" part is really important. Gradual
| typing makes a lot of sense when you are trying to retrofit
| some amount of static checking onto an existing enormous corpus
| of dynamically typed code. That's the case for TypeScript with
| JavaScript and Elixir with Elixir and Erlang.
| nerdponx wrote:
| What about Julia?
| chubot wrote:
| Oh yeah, as far as I know Elixir has a lot of calling back
| and forth with Erlang code. So that makes for a super tricky
| type system problem.
|
| I think the macros make it even harder. Elixir appears to be
| done almost all with macros -- there are lots of little
| "compilers" to Erlang/BEAM.
| 7thaccount wrote:
| Raku (formerly known as Perl 6 and a radically different
| language than Perl 5) uses gradual typing on purpose. It's a
| cool language that has a lot of advanced ideas, but has
| basically been in either the design or beta stage for like
| two decades.
| fuzztester wrote:
| >for like two decades.
|
| IOW, Raku is a gradual type of language.
| YorickPeterse wrote:
| You're right about this applying to new languages. I've added
| a note to the article to (hopefully) make this more clear.
| layer8 wrote:
| What you can do is the opposite, integrate a "dynamic" type
| into a statically-types language, like C# does:
| https://learn.microsoft.com/en-us/dotnet/csharp/advanced-top...
|
| This lets you use dynamic typing when you want, and enables
| more seamless interoperability with dynamically-typed
| languages.
| coldtea wrote:
| Well, there's no memo (real or as a manner of speaking). It's
| just this person's preference.
|
| I think gradual typing is a nice concept, and his arguments
| against it amount to "gradual typing is not stating typing",
| which is like the whole point. E.g. he goes on how the compiler
| can't do some optimizations on functions using gradual typing,
| but, well, it isn't supposed to anyway.
|
| The benefit of gradual typing is that you can make your program
| fully dynamic (e.g. for quick exploration), and if you want
| more assurances and optimizations make it fully static, or if
| you just want that for specific parts, do them static. And you
| have the option to go for any of those 3 things from the start.
| YorickPeterse wrote:
| The problem about the whole "it's faster (productivity wise)
| than static typing" has, as far as I know, never actually
| been proven (certainly not through repeated studies).
|
| Having worked with both dynamically and statically typed
| languages extensively, I never felt I was _more_ productive
| in a dynamically (or gradually) typed language compared to
| one that was just statically typed. For very basic programs
| you may spend a bit more time typing in a statically typed
| language due to having to add type annotations, but typing
| isn't what I spend most of my time on, so it's not a big
| deal.
|
| In addition, that work you need to (potentially) pay upfront
| will help you a lot in the long term, so I suspect that for
| anything but the most basic programs static typing leads to
| better productivity over time.
| kybernetikos wrote:
| I think it's unfair to criticise the lack of studies for
| that specific question without acknowledging that there are
| exceedingly few studies that show a benefit for static
| typing despite the fact that a huge number of people _feel_
| that there must be an effect.
| lylejantzi3rd wrote:
| _" either make your language statically typed or dynamically
| typed (preferably statically typed, but that's a different
| topic), as gradual typing just doesn't make sense for new
| languages."_
|
| Is that because of type inference?
| cies wrote:
| What part of the statement "is" because of type inference?
| marcosdumay wrote:
| Your question doesn't make a lot of sense. The entirety of
| gradual typing works by type inference, as does the static
| typing on any new language.
| Jtsummers wrote:
| [delayed]
| sesm wrote:
| Looking at the table in the end of the article: notice how Scala
| and Elixir both took only 3 years, because they were targeting an
| existing platform. Clojure took only 2 years and was developed by
| a single person.
| fsckboy wrote:
| > only 3 years, because they were targeting an existing
| platform. Clojure took only 2 years and was developed by
| _targeting_ a single person.
| zengid wrote:
| > "Oh, and good luck finding a book that explains how to write a
| type-checker, let alone one that covers more practical topics
| such as supporting sub-typing, generics, and so on"
|
| I bought _Practical Foundations for Programming Languages_ by
| Harper and _Types and Programming Languages_ by Pierce and I just
| can't get through the first few pages of either of them. I would
| love to see a book as gentle and fun as _Crafting Interpreters_
| but about making a static ML like language without starting with
| hardcore theory. (Bob, if you're listening, please make a
| sequel!)
| PhilipRoman wrote:
| I would love to know more about what the author found difficult
| regarding type checking. As long as you don't screw up your
| semantics to the point of needing a full blown constraint
| solver there should be no issues.
|
| Edit: by "screwing up semantics" I mostly mean the combination
| of overloading and implicit conversions, which is known to
| cause issues in Java, C++, etc.
| YorickPeterse wrote:
| The problem for me was that I had a rough idea of how to
| implement (essentially it's similar to a recursive-descent
| parser), but I had a difficult time finding appropriate
| resources to confirm or deny whether my idea was solid, as
| well as tips and what not.
|
| Basically, the existing material is a bunch of existing
| incredibly complicated implementations, the odd blog post
| that just throws a bunch of code your way without really
| explaining the why/thought process behind it, and books that
| aren't worth the money.
|
| The result is that you can of course piece things together
| (as I did), but it leaves you forever wondering whether you
| did it in a sensible way, or if you constructed some weird
| monstrosity.
|
| To put it differently: you can probably build a garden by
| digging some holes and throwing a few plants around, but
| without the right resources it can be difficult to determine
| what the impact of your approach may be, and whether there
| are better ways of going about it. Oh and I'm aware there are
| resources on gardening, it's just a metaphor :)
| Q6T46nT668w6i3m wrote:
| As someone who has written many compilers and type
| checkers, I agree. There's very little information online
| about the subject. I think part of the issue, for me, was
| psychological: I felt like I was missing some
| implementation theory that was presented alongside other
| compiler subjects (e.g., LALR) when the reality is that
| you're mostly implementing very simple Boolean operations.
| ww520 wrote:
| While helping a bit, it's difficult to learn or reverse
| engineer from existing type checking code because a lot of
| them are mundane repetitive code implementing some high
| level theory and algorithms. The actual code is too far
| remote from the theory. You really want to start from the
| theory and the overall picture.
|
| The Dragon book has a chapter on type checking. It gives
| explanations on many topics. It has plenty of examples. It
| has type treatments on different areas of a language, like
| expression, array, struct, function, pointer, etc.
|
| Despite being really old, its ideas and explanation on the
| topic are still relevant.
| mabster wrote:
| I think the larger writings like books are generally going
| to be written by academics so they'll be rigorous and hard
| to read.
|
| So that leaves blog posts for most developers actually
| implementing this stuff.
|
| But the solution here is that when you finally figure out a
| good strategy to deal with something muddy like this is to
| write that better blog post :)
| YorickPeterse wrote:
| I'm planning on doing something similar to what I did for
| pattern matching [1]: basically building something
| entirely standalone that fits in 2k LOC or so, and
| explains the basics (i.e. nominal typing plus basic sub-
| typing), hopefully such that people can then take that
| and extend it.
|
| As for _when_ I'll do that, that depends on when I can
| convince my inner critic to actually commit to the idea
| :)
|
| [1]: https://github.com/yorickpeterse/pattern-matching-
| in-rust
| paulddraper wrote:
| TypeScript type-checking is quite complicated. I'm sure no
| human being on earth could pass a test of "does this compile"
|
| But that's an exception, and deliberately decided to be
| complex.
| alex_lav wrote:
| I know nothing about how one would make a type checker, but
| it sort of feels like your comment is "As long as you don't
| encounter any issues, there won't be any issues", no?
| chubot wrote:
| I'm in the same boat as you -- here are the two best resources
| I found:
|
| https://mukulrathi.com/create-your-own-programming-language/...
|
| https://jaked.org/blog/2021-09-07-Reconstructing-TypeScript-...
|
| I read through the first 10 chapters of TAPL, and skimmed the
| rest. The first 10 chapters were good to remind myself of the
| framing. But as far as I can tell, all the stuff I care about
| is stuffed into one chapter (chapter 11 I think), and the rest
| isn't that relevant (type inference stuff that is not
| mainstream AFAIK)
|
| This is also good:
|
| https://github.com/golang/example/blob/master/gotypes/README...
|
| And yeah some of us had the same conversation on Reddit --
| somebody needs to make a Crafting Interpreters for type
| checking :) Preferably with OOP and functional and
| nominal/structural systems.
|
| ---
|
| Also, it dawned on me that what makes TAPL incredibly difficult
| to read is that it lacks example PROGRAMS.
|
| It has the type checkers for languages, but no programs that
| pass and fail the type checker. You are left to kind of imagine
| what the language looks like from the definition of its type
| checker !! Look at chapter 10 for example.
|
| I mean I get that this is a math book, but there does seem to
| be a big hole in PL textbooks / literature.
|
| Also I was kinda shocked that the Dragon Book doesn't contain a
| type checker. For some reason I thought it would -- doesn't
| everyone say it's the authoritative compiler textbook? And IIRC
| there are like 10 pages on type checking out of ~500 or more.
| zengid wrote:
| Thank you so much! This looks like some good morning-with-
| coffee reading!
| coldtea wrote:
| > _" In reality, gradual typing ends up giving you the worst of
| both dynamic and static typing: you get the uncertainty and lack
| of safety (in dynamically typed contexts) of dynamic typing, and
| the cost of trying to fit your ideas into a statically typed type
| system. I also found that the use of gradual typing didn't
| actually make me more productive compared to using static
| typing._
|
| Well, that's like, your opinion, man...
| orthoxerox wrote:
| "Avoid writing your own code generator, linker, etc"
|
| There's a certain dearth of pluggable code generators and
| linkers. Well, not on GNU/Linux, where you get both as(1) and
| ld(1) practically out of the box, but making your compiler emit a
| PE/COFF on Windows is a pain. You either bring your own homemade
| codegen and linker or use LLVM, using Microsoft's ml64.exe and
| link.exe is incredibly impractical.
| packetlost wrote:
| As someone who has worked with massive typed Python codebases, I
| 100% agree with the author on Gradual Typing. It's literally the
| _worst_ of both worlds. It 's actually even worse than that
| because it gives the _illusion_ of some safety when there isn 't
| any, especially in Python where most of the tooling "fails open"
| by default and won't tell you something is wrong despite having
| annotations.
| Q6T46nT668w6i3m wrote:
| Any? I regularly find bugs. I don't find every bug, but finding
| some bugs is better than none. Especially for the minimal cost
| of writing annotations.
| lmm wrote:
| > I don't find every bug, but finding some bugs is better
| than none.
|
| I used to think this, but based on experience I'm now less
| convinced. Finding most bugs, like real static typing does,
| is great; you can significantly reduce your test coverage and
| iterate with more confidence. Finding a few bugs is pretty
| useless if you're not finding enough to actually change your
| workflow.
| LegibleCrimson wrote:
| Finding a few bugs is very useful if they're the kind of
| bugs that can cause problems in production but usually not
| in development or testing, like not checking an optional
| that is very rarely null.
|
| It's not about workflow or finding enough bugs, but finding
| bugs that you might not have otherwise seen can be
| monumentally beneficial.
| lmm wrote:
| > Finding a few bugs is very useful if they're the kind
| of bugs that can cause problems in production but usually
| not in development or testing, like not checking an
| optional that is very rarely null.
|
| There's a kind of excluded middle here though. Either
| that kind of bug hits production often enough to matter -
| in which case a checker that catches it sometimes isn't
| good enough, you need a checker that eliminates it
| completely. Or it doesn't hit production often enough to
| matter, in which case a checker is of limited use.
| LegibleCrimson wrote:
| I disagree, as somebody who has also worked with tons of type-
| hinted Python code. Gradual typing is obviously worse than real
| static typing, but it's a step up from full dynamic typing. It
| has caught many bugs for me before hitting them in runtime, and
| provides good documentation about what I can expect a function
| to accept and return without forcing me to read prose.
|
| Type hints don't provide any safety, though. That was never the
| goal, given that they're strictly optional and don't really
| exist at runtime anyway (though I have written some
| experimental monstrosities that used annotations for code
| generation at runtime). They're documentation in a standard
| form that static analysis tools can leverage.
|
| I really can't imagine a situation where having type hints in
| Python is worse than simply not having them. They're not the
| worst of both worlds, they're a compromise with some of the
| benefits and drawbacks of each.
| ric2b wrote:
| How is it worse than no typing? If you're not testing
| adequately because you think type safety is enough, you done
| f'd up.
| tabtab wrote:
| The only "good" programming language is the language I make!
| Everybody thinks different and wants to optimize for different
| things. There is no existing language I've found that I "love";
| they each have features I like but none have all the features
| together.
|
| I've drafted up a language called "Moth" that has a lot of "meta
| power" to program block scope any way you want, as most languages
| hard-wire scoping rules, which I find limiting. Things like
| "classes", "functions", while-loops etc. would be defined by
| libraries, NOT the language. It's like lambda's on steroids and
| without bloated arrow syntax. But it may run slow as molasses, as
| scoping meta power adds lots of compiler/interpreter indirection.
|
| However, it may turn out that only a few scoping rules are
| practical in most cases, and the compiler could then optimize for
| those. It would then only be slow if you are doing something
| "weird" with scope. Stick to a fixed known set, and things zip
| along. But finding that set requires R&D and road testing.
| bsder wrote:
| > Avoid self-hosting your compiler
|
| Not sure this is so problematic anymore.
|
| The Zig folks targeted WASM so that they can bootstrap without
| needing a second compiler implementation. Compilers don't need a
| lot of POSIX in order to be functional.
___________________________________________________________________
(page generated 2023-11-14 23:00 UTC)