[HN Gopher] From Languages to Language Sets
       ___________________________________________________________________
        
       From Languages to Language Sets
        
       Author : whatever3
       Score  : 58 points
       Date   : 2025-03-14 07:12 UTC (3 days ago)
        
 (HTM) web link (gist.github.com)
 (TXT) w3m dump (gist.github.com)
        
       | andyferris wrote:
       | One thing I'll note is we tend to use languages from different
       | levels in different settings (front end, back end, systems) and
       | we spend an awful lot of time writing glue code to get them to
       | talk to each other.
       | 
       | A major advantage of the proposed approach is automated FFI and
       | serialization/deserialization between languages in the same
       | language set. RustScript would be able to accept a struct or enum
       | from Rust or RustGC, and vice-versa. You could have a channel
       | with different languages on either end.
       | 
       | You can also see that we _want_ something like this, e.g. we bolt
       | TypeScript on top of JavaScript, and types onto Python. If
       | JavaScript (or python) were designed so they could be more easily
       | compiled (notably, no monkey patching) then they would support
       | level 2 as well.
       | 
       | I have been thinking of level 2 or 1 languages that support the
       | higher levels. This is a really good framing. (The problem with
       | going the other way is the implementation decisions in the
       | interpretter often constrain how the compiler can work, e.g.
       | CPython is dominant because all the libraries that make use of
       | the CPython FFI, and similarly for NodeJS. It is easier to
       | interpret a constrained language than to compile a dynamic
       | language designed with an interpretter in mind).
        
         | sitkack wrote:
         | Back when I did some high perf Python, I'd define my data at C
         | structs and bump allocate those structs in a list using the
         | cffi.
         | 
         | It is not unlike defining your data model for SQL so that you
         | can have sane data access.
        
           | zahlman wrote:
           | >bump allocate
           | 
           | The term isn't familiar to me, and when I try to look it up I
           | get almost exclusively Rust-related results. I guess you mean
           | https://en.wikipedia.org/wiki/Region-based_memory_management
           | , which I grew up calling "pool allocation".
        
             | sitkack wrote:
             | I am using it a euphemism for reserving address space and
             | then committing pages as your list grows. This isn't
             | preallocating memory, just address space.
             | 
             | But pool allocation works as well. The idea is to go from a
             | chonky representation to a portable compact representation
             | of a C-struct but still have the Python accessors to this
             | data look idiomatic.
        
         | eterps wrote:
         | This a 100%. It's madness that languages are effectively siloed
         | from each other.
        
       | teaearlgraycold wrote:
       | I'm a strong supporter of adding an automatic GC to Rust.
       | Although it seems difficult to justify as RustGC code wouldn't be
       | trivial to convert to traditional Rust. But going in the opposite
       | direction should be trivial.
        
       | gabrielsroka wrote:
       | 2022
       | 
       | https://hn.algolia.com/?query=From%20Languages%20to%20Langua...
        
       | munificent wrote:
       | _> One language could combine the 2nd and 3rd level though. A
       | language that can be interpreted during development for fast
       | iteration cycle, but compiled for better performance for
       | deployment. There isn't such a language popular today though._
       | 
       | I'm not sure if Dart counts as "popular", but it otherwise fits
       | this bill. It has a JIT and can startup pretty quickly and
       | interpret on the fly. You can also hot reload code changes while
       | a program is running. And it can ahead-of-time compile to
       | efficient machine code when you're ready to ship.
        
         | layer8 wrote:
         | Many interpreted languages use an intermediate representation
         | and/or JIT compilation internally, like for example Python with
         | its _.pyc_ files. And Java as a level-2 language only compiles
         | to bytecode ( _class_ files) which by default is then
         | interpreted, and typically only JIT-compiled for "hot" code.
         | The distinction between levels 3 and 2 is more about how the
         | application is distributed for execution, in source-code form
         | vs. in some compiled binary form.
        
       | rickcarlino wrote:
       | This is a better taxonomy of what a language is rather than the
       | dated concept of "High-level" vs. "Low-level".
        
       | emidln wrote:
       | This is one of the reasons I like Clojure. There are very useful
       | dialects with broad overlap between:
       | 
       | Browser / JavaScript environments -> ClojureScript
       | 
       | General Purpose (JVM) -> Clojure
       | 
       | Fast Scripting -> Babashka (although I've used ClojureScript for
       | this in the past)
       | 
       | C/C++ Interop (LLVM-based) -> Jank (new, but progressing rapidly
       | and already useful)
       | 
       | I can largely write the same expressive code in each environment,
       | playing to the platform strengths as needed. I can combine these
       | languages inside the same project, and have libraries that have
       | unified APIs across implementation. I can generally print and
       | read EDN across implementations, provided I register the right
       | tag handlers for custom types (this is one area jank still has to
       | catch up). Reader conditionals allow implementation-specific code
       | as needed.
       | 
       | I'm really excited about Jank giving me a good alternative to
       | JNI/JNA/Panama when I need my Clojure to touch OS parts the JVM
       | hasn't wrapped.
        
       | jasonthorsness wrote:
       | Especially with LLMs to assist we don't gain much anymore from
       | making everything one syntax, one language, etc. Projects like
       | Dotnet Blazor/ASP.NET or Python Streamlit/Dash IMO are forced and
       | are more trouble than they are worth. The OP suggestion, where
       | everything is Rust, has the same problem; it's too forced.
       | 
       | We should embrace the domain-specific niceties; there are room
       | for lots of languages, they can iterate more quickly, try new
       | things, and specialize syntax to the domain.
        
       | HumanOstrich wrote:
       | TLDR; Let's rewrite everything in 3 languages: Rust, RustGC, and
       | RustScript!
       | 
       | Ugh.
        
         | froh wrote:
         | That's missing out on the nice idea of four (or five) language
         | "levels"
         | 
         | > 4: Interpreted, dynamically typed: JavaScript, Python, PHP
         | 
         | > 3: Interpreted, statically typed: Hack, Flow, TypeScript,
         | mypy
         | 
         | > 2: Compiled with automatic memory management (statically
         | typed): Go, Java (Kotlin), C#, Haskell, Objective-C, Swift
         | 
         | > 1: Compiled with manual memory management (statically typed):
         | Rust, C, C++
         | 
         | > There is a 0th level, assembly, but it's not a practical
         | choice for most programmers today.
         | 
         | and it's also missing out on the generic hypothesis that a
         | language is needed between levels 2 and 3, which is interpreted
         | for fast turn-around times but also compilable for fast run
         | time.
        
           | vips7L wrote:
           | Hot reload has existed for decades. I don't see how that is
           | missing.
           | 
           | I really think the person your replying to really is just
           | showing dissatisfaction that once again someone is trying to
           | force Rust where it doesn't belong. It's exhausting.
        
       | jimbokun wrote:
       | Where would Haskell go?
       | 
       | Erlang and Elixir?
        
         | azhenley wrote:
         | Haskell is listed.
        
         | siknad wrote:
         | Perhaps together with Agda (compiles to Haskell, has FFI to it,
         | is more higher-level), some not-pure ML, and maybe Rust or ATS?
        
       | notarobot123 wrote:
       | I think Peter Naur's description of levels of computation is a
       | better one for considering an actual layering of levels of
       | abstraction:
       | 
       | > Each level is associated with a certain set of operations and
       | with a programming language that allows us to write or otherwise
       | express programs that call these operations into action. In any
       | particular use of the computer, programs from all levels are
       | executed simultaneously. In fact, the levels support each other.
       | In order to execute one operation of a given level, several
       | operations at the next lower level will normally have to execute.
       | Each of these operations will in their turn call several
       | operations at the still lower level into execution.
       | 
       | The old term "problem-oriented languages" seems to still be quite
       | useful. Programming languages are always focused on allowing the
       | programmer to solve a set of problems and their features hide
       | irrelevant details.
       | 
       | These language sets seem like a helpful grouping of features that
       | suit particular problem domains but I don't think it works as a
       | taxonomy of levels of abstraction.
        
       | kerkeslager wrote:
       | > Now let's address level 4. Big players sit at this level,
       | perhaps the most popular languages by headcount of their
       | programmers. The problem with a lack of static typing is that
       | it's hard to work on such code in groups and at scale. Every
       | successful business started with those languages eventually
       | rewrites their codebase to use one of the "lower level" languages
       | because big codebases written by many people are hard to maintain
       | and modify without the support of a static type-checker. They are
       | still great languages for solo, small projects, especially if the
       | code can be easily automatically tested.
       | 
       | This is total made up nonsense. I've worked in Python for over a
       | decade, and at multiple successful companies that have been
       | running quarter-million plus line Python codebases for 8+ years.
       | 
       | Proponents of static typing like to sound alarms that it's
       | impossible to scale dynamic codebases when they lack the
       | experience in those languages to know people solve scaling
       | problems in those languages.
       | 
       | I'm not hating on static languages, but I think they involve more
       | tradeoffs than proponents of static typing admit. Time spent
       | compiling is pretty costly, and a lot of codebases go to great
       | lengths to somewhat bypass the type system with dependency
       | injection, which results in much more confusing codebases than
       | dynamic types ever did.
       | 
       | Meanwhile, many of the worlds largest and longest-maintained
       | codebases are written in _C_ , which is only half-assed type
       | checked at any point, and is much harder to maintain than dynamic
       | languages. The idea that projects reach some point of
       | unweildiness where _every_ one of them gets rewritten is just not
       | correct.
       | 
       | I might have gone a bit easier on this if the author hadn't said
       | " _Every_ successful business... "--the word "every" really is
       | just way too far.
       | 
       | EDIT: I'll also note that just because a language isn't
       | statically typed, doesn't mean it gains no benefit from type
       | checking. JavaScript and Python are not created equal here:
       | JavaScript will happily let you add NaN and undefined, only to
       | cause an error in a completely unrelated-seeming area of the
       | codebase, whereas Python generally will type check you and catch
       | errors pretty close to where the bug is.
        
         | svilen_dobrev wrote:
         | i completely agree. i have lead a team of 3 (three, incl. me)
         | which has made and run completely "untyped" 90KLoc python +
         | 90KLoc javascript for years (well, about 25% was generated,
         | from another 1%. Meta programming, yes). And a few other
         | similar codebase magnitudes and team-counts, before.
         | 
         | IMO rewriting happens mostly because going to lower-level of
         | the needed proficiency/understanding - once the product why-
         | what-how is more-or-less discovered, its code can be
         | commoditized and hardened, kind-a. Dynamic stuff is very
         | powerful == becomes too powerful (and "magic").
         | 
         | There is quite some wishful thinking around what so-called
         | static-typing (which is actually static type-hinting) in
         | dynamic languages, hoping and believing that declaring
         | something Float, guarantees it being Float at runtime.. which
         | is nonsense. In Ada, and few other _runtime_ type-and-range-
         | etc-checking languages - yes. But in plain ones.. nope. C++,
         | Java, whatever - noone checks things at runtime. Most of those
         | do not have a way to know what some n-bytes represent, hoping
         | it matches the expected layout (i.e. type). While, say, python
         | very well knows what each and every object is. If asked.
         | 
         | Of course, one can build such real-runtime checkers, and apply
         | them where/when it is needed and makes sense - instead of
         | blanket policy everywhere, but noone bothers. (Funny thing is,
         | when i made one such library 15y ago, i was spit at and told to
         | go code in java. And, even i haven't since then stumbled on
         | pressing need to use it myself. Having 10 asserts (or
         | constraint checks) in some 10kLoc does not justify whole
         | library)
         | 
         | That said, i think something like language-verticals might be
         | useful. And/Or gradual hardening, on piece-meal basis. At least
         | a standartized way for going up/down or stricter/relaxed, from
         | wherever one is.
        
           | Snacklive wrote:
           | > But in plain ones.. nope. C++, Java, whatever - noone
           | checks things at runtime. Most of those do not have a way to
           | know what some n-bytes represent
           | 
           | But then my question is, what are you doing that you need to
           | manually check for types ? I mean i get it at some point,
           | usually at the time of user input usually you need to run
           | checks to actually convert some input into a valid type. But
           | once it is inside your program you don't need to check
           | anymore because well... static typing and all that, you
           | should know what you have in every step just at a glance
        
       | tmtvl wrote:
       | A language which can be either interpreted or compiled doesn't
       | exist? Nobody tell the Common Lispers, they'd vanish in a puff of
       | logic.
        
       | flufluflufluffy wrote:
       | Level 4 and level 3 have equal performance. The benefit is in the
       | developer experience. But also just use what you like man. Or
       | what fits the task at hand. Most of the "problems" this and other
       | articles like it bring up are so overblown and exaggerated.
        
       | layer8 wrote:
       | There is something to be said for the three languages ("levels")
       | to actually look sufficiently different from each other, so that
       | when looking at some code it's immediately clear which one it's
       | in. Making them too similar increases the likelihood of mistaking
       | which one you're in, and applying the mindset of one to the
       | other.
       | 
       | Another reason to do that is that the different levels are
       | amenable to different affordances, and have different trade-offs
       | in their design. For example, at level 4 you may want to go for a
       | more BASIC-like syntax, without semicolons, and commands without
       | argument-list parentheses.
        
       | chubot wrote:
       | I generally agree with the 4 tier categorization:
       | 1. C/C++/Rust         2. Java/Go/OCaml         3. MyPy,
       | TypeScript         4. Python, JavaScript
       | 
       | But I'd also add 2 or 3 more tiers:                   5. String-
       | ish languages without GC - Shell, Awk, Make, CMake  [1]
       | 6. Configuration Languages - YAML / TOML - declaring data
       | structures [2]         7. Data Notations - JSON, HTML, CSV -
       | Objects, Documents, Tables [3]
       | 
       | The goal of YSH is actually to *unify tiers 4, 5, 6, and 7* under
       | one language. The slogan I've been using is "minimal YSH is
       | shell+Python+JSON+YAML"
       | 
       | Instead of having Unix sludge (autotools - m4 generating make)
       | and Cloud sludge (Helm - Go templates generating YAML), you have
       | one language                   - YSH is the code dialect -- it is
       | a shell with real data types like Python           - and with
       | reflection like Ruby/Python, not generating text              -
       | Hay (Hay Ain't YAML) is the data dialect           - and we have
       | built-in JSON, etc.
       | 
       | This is a hard design challenge, but I just made a release with
       | an overhaul of Hay - https://oils.pub/release/0.28.0/
       | 
       | Hay version 1 was hard-coded in the interpreter -
       | https://oils.pub/release/0.28.0/doc/hay.html
       | 
       | But we realized it's actually better to self-host it in YSH,
       | using YSH reflection. We will be testing this by rewriting Hay in
       | YSH
       | 
       | ---
       | 
       | So that's our language design response to
       | https://news.ycombinator.com/item?id=43386115
       | 
       | > It's madness that languages are effectively siloed from each
       | other.
       | 
       | Instead of tiers 4, 5, 6 being silo'd, we have them all under YSH
       | and the Oils runtime (which is tiny, 2.3 MB of pure native code).
       | 
       | (As a bonus, OSH also runs on the Oils runtime, and it's the most
       | bash-compatible shell!)
       | 
       | ----
       | 
       | [1] _Garbage Collection Makes YSH Different_ -
       | https://www.oilshell.org/blog/2024/09/gc.html
       | 
       |  _Shell, Awk, and Make Should Be Combined_ -
       | https://www.oilshell.org/blog/2016/11/13.html - all these
       | languages lack GC!
       | 
       | [2] Survey of Config Languages - https://github.com/oils-for-
       | unix/oils/wiki/Survey-of-Config-... - divides this category into
       | 5 tiers:                   1. Languages for String Data
       | 2. Languages for Typed Data         3. Programmable String-ish
       | Languages         4. Programmable Typed Data         5. Internal
       | DSLs in General Purpose Languages
       | 
       | [3] _Zest: Notation and Representation_ addresses this -
       | https://www.scattered-thoughts.net/writing/notation-and-repr...
       | 
       | YSH also has a common subset with J8 Notation (which is a
       | superset of JSON)
        
       | Peteragain wrote:
       | A nice summary of the issues is my top-level comment. So Java, Vs
       | JavaScript is in here somewhere. My take on it is that java keeps
       | getting extended to look more like JavaScript, and inevitably
       | becomes slower.
        
       ___________________________________________________________________
       (page generated 2025-03-17 23:02 UTC)