[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)