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