13 ms·
What's next for language design? (2017)
- deleted 5y ago[deleted]
- verdagon 5y agoSome more things I see coming soon: * Decoupled allocation, to use any allocator with any existing code. Cone has some really cool things on the way here, where we can package up allocators into modules and others can import them and use them [0]. Odin is also trailblazing here, with its implicit allocator "context" parameter [1]. Zig does this in an explicit way in its standard library [2]. * First-class isolated regions, where certain areas of memory cannot point to each other, but within a particular region we can freely mutably alias. Vale [3] and Verona [4] are doing some interesting experiments here. * Better static analysis, to close the gap between memory-managed languages and C. Lobster's algorithm is very impressive here [5], and Vale is attempting an "automatic Rust" approach [6]. * True "structured parallelism", where we can "freeze" all existing memory and freely access it in parallel from a loop's body. Pure functional languages might be able to do this, but it would be interesting in an imperative language. Rust can almost do this, but can only share things with Sync. * Blending the borrow checker with other paradigms. Cone is going all-in on this concept [7], and looks really promising. The pieces are also there in D and Vale, but we'll see! I also have some things on my wish list (full deterministic replayability!) but they aren't really on the horizon yet. (Disclaimer: I work on Vale, which aims to bring many of these features into the mainstream) [0]: https://cone.jondgoodwin.com/coneref/refregionglo.html https://cone.jondgoodwin.com/coneref/refregionglo.html [1]: https://odin-lang.org/docs/overview/#allocators https://odin-lang.org/docs/overview/#allocators [2]: https://ziglearn.org/chapter-2/ https://ziglearn.org/chapter-2/ [3]: https://vale.dev/blog/zero-cost-refs-regions https://vale.dev/blog/zero-cost-refs-regions [4]: https://www.microsoft.com/en-us/research/project/project-verona/ https://www.microsoft.com/en-us/research/project/project-ver... [5]: https://aardappel.github.io/lobster/memory_management.html https://aardappel.github.io/lobster/memory_management.html [6]: https://vale.dev/blog/hybrid-generational-memory https://vale.dev/blog/hybrid-generational-memory [7]: https://cone.jondgoodwin.com/coneref/refperm.html https://cone.jondgoodwin.com/coneref/refperm.html
- c0balt 5y agoI might also want to add that rust allows decoupled allocation rn. There are some popular allocators, like jemalloc, but also some project specific ones, especially for some custom OS no-std projects. Edit: See https://docs.rust-embedded.org/book/collections/index.html#using-alloc https://docs.rust-embedded.org/book/collections/index.html#u... for a through explanation
- moldavi 5y agoSomething about Odin I like is that you can have multiple allocators, and use a bump allocator for just a specific call (and its subcalls), and afterward free it all at once, and go back to normal heap allocation. It would be cool if Rust offered a built-in way to do that too.
- ameliaquining 5y agoStrictly speaking, Rust doesn't need this as a built-in language feature, because its design allows it to be implemented as a third-party library: https://docs.rs/bumpalo https://docs.rs/bumpalo The biggest problem is that there's some awkwardness around RAII; I'm not sure whether that could have been avoided with a different approach. Of course, ideally you'd want it to be compatible with the standard-library APIs that allocate. This is implemented, but is not yet at the point where they're sure they won't want to make backwards-incompatible changes to it, so you can only use it on nightly. https://doc.rust-lang.org/stable/std/alloc/trait.Allocator.html https://doc.rust-lang.org/stable/std/alloc/trait.Allocator.h... Or are you suggesting that the choice of allocator should be dynamically scoped, so that allocations that occur while the bump allocator is alive automatically use it even if they're in code that doesn't know about it? I think it's not possible for that to be memory-safe; all allocations using the bump allocator need to know about its lifetime, so that they can be sure not to outlive it, which would cause use-after-free bugs. I'm assuming that Odin just makes the programmer responsible for this, and if they get it wrong then memory corruption might occur; for a memory-safe language like Rust, that's not acceptable.
- 5y ago
- grumpyprole 5y agoI would add sructural types, for example anonymous (extensible) records and variants. Nominal types are overused in nearly all programming languages, even futuristic ones like Haskell. The default type definition should be a structural type, because it is easy to then simply name it if required. Every C or Java programmer writes a function definition in terms of a tuple of parameters, despite not having first class tuples. Functional programming languages can also return tuples, but where are the anonymous records? These would allow defining functions with named arguments essentially for free.
- yeputons 5y agoTypeScript's types are structural, and I don't consider this to be a good thing. It's useful for JavaScript interop, yes, but just because two values have the same representation and method names does not mean they're interchangeable. Case in point: time units. So while there may be some use of structural subtyping, I don't think it's codebase-wide.
- grumpyprole 5y agoHere's a counter example. I've seen numerous Java projects define a nominal predicate type, for example com.google.common.base.Predicate. None of these are interoperable without writing adapter code. ML and Haskell would essentially use a structural type: t -> bool Much simpler and easier to consume. How would you assign a nominal type to the result of a SQL query? So there are arguments on both sides. My point was that structural types can always easily be turned into a nominal type, but not the other way around. Therefore they should be the default.
- de_keyboard 5y agofunction types are structural in most nominally-typed languages I have used, perhaps a poor example?
- grumpyprole 5y ago
- gameswithgo 5y agoF# has had a few of these features for a long time
- dharmaturtle 5y agoGonna shoutout F#'s unit-of-measure types > It's "small" but rather important not to mix units! With unit of measure, it's possible to easily/simply create types like CustomerId, which is actually a Guid/Int under the covers. Means you can't pass a CustomerId to something that expects an OrderId. These types are erased at compile time, so there's zero effect on runtime performance. It's lovely.
- tadfisher 5y agoSee also: Haskell newtypes and Kotlin value classes (née inline classes).
- sullyj3 5y agoDoes Kotlin have the equivalent of GeneralizedNewTypeDeriving or whatever is required to make math operators work without boilerplate?
- tsimionescu 5y agoOne unexpected aspect of unit-of-measurement types is that they don't generalize well at all to anything more complex than basic arithmetic. For example, it's very hard to create a type-safe library that allows you to compute the dot product of (1m 1Hz) and (1Hz 1m) and get 2m/s, but doesn't allow you to accidentally compute the dot product of (1m 1Hz) with itself.
- deleted 5y ago[deleted]
- b3morales 5y ago> Parametric mutability, permission / state polymorphism, ??? > ... does the system of function types and effects scale to expressing polymorphism over the mutable-ness of a type ... That's a very thought-provoking handful of sentences. Anyone know of work on this question/area?
- stevenhuang 5y agoPerhaps an example that immediately comes to mind is c++ overloaded functions with mutable and immutable versions of the same base type (const ref, non const ref, rvalue reference).
- mikewarot 5y agoMixing procedural and reactive code in the same program. Imagine if A := B worked in the normal pascal assignment sense, but A :<<: B caused A to be recalculated every time B changed, like a magical assignment operator. If you assigned something to the system clock, it would act like an interval timer, for example.
- bsiemon 5y agohttps://svelte.dev/ https://svelte.dev/ is an example of this idea.
- titzer 5y agoAn issue would be spooky action at a distance. A ripple effect of a single assignment could cause a cascade of computations. What order do they happen in? How do you find them all?
- mikewarot 5y agoUse an algorithm similar to excel spreadsheets, mark a result dirty, and ripple through all the dependencies.
- sullyj3 5y agoThis is always comprehensible in excel because state changes only ever come about as a result of a user changing a value in a cell. In the general case where there are a bunch of different asynchronous sources of change, this could become pretty confusing.
- matu3ba 5y agoUnfortunately the author is not very explicit on the interesting formal stuff: 1.implicit and 2.explicit proof-carrying code and 3. verifying compilers with its cost (there are as of today exactly 2 general usable and fully verified compiler implementations: compcert and cakeml), 4. lowering languages to Isabelle or other interesting proof systems as compiler backends (or using codegen for source code and proof like what cogent does). The author appears also not to know formally proved and domain specific languages, which are "Effect systems" (they check if conditions are uphold) to generate C code. Generally life is a tradeoff and the same holds for showing semantically expressive properties (or one needs a proof system). Most languages rely on LLVM and its linker with linker speak, which are both not formally proven to be consistent and both have no model. The spec also does only describe basic hardware abstraction and without a formal model from CPU vendors this wont improve much. "Cost-model type systems": only sel4. check the blog of the head with papers why https://microkerneldude.org/ https://microkerneldude.org/
- ncmncm 5y agoThe author does, in fact, know about effect systems. Generating C code is pointless unless a C compiler is the only way you have available to emit machine instructions.
- deleted 5y ago[deleted]
- haolez 5y agoI'd bet on a future language that makes it easy to program professionally on mobile devices. Yes, I know that for us "real" programmers this is dreadful, but it would make programming more accessible and this could have interesting network effects on our society. I'd imagine that this language would have some traces of visual programming (like Enso[0]) and the denseness of APL[1]. [0] https://enso.org https://enso.org [1] https://aplwiki.com/wiki/Simple_examples https://aplwiki.com/wiki/Simple_examples
- ncmncm 5y agoProgramming on mobile devices is hard because that is the way the platform owners like it. So, first, mobile devices need to be busted loose from the gatekeepers.
- wruza 5y agoThis list, together with already mainstream features, turns a programmer’s learning curve into an uncompromising cliff. It’s clear that right now big software has to be formal to live longer and stay healthy, but for me it feels like we’re losing something important on this way. Computers ought to be our helpers which could understand our plans and implement them properly. Instead we are burying ourselves and those who will come later in what is essentially a deep math. And our software doesn’t even get faster or better, it just fits whatever performance:annoyance ratio is acceptable at the end of the day. I think, and this is more of an intuitive rather than an informed guess, that the current practical languages are still too low level and that may be one of big reasons why software development is so complex. You probably feel it too, when you have to either A) go find, copy and fine-tune yet another boilerplate or a snippet, making it again too hairy to use as is next time, or B) use a standard solution which almost implemented another programming language on top of its configuration and isn’t really much easier to use than if it were just a from-scratch code. Shovels get better, but we are still digging careers with them. And we had predecessors of a theoretical language which could be high-level enough to make programming great again. E.g. FoxPro with all its DOS restrictions was a platform where one could read, write, iterate, update data, never thinking how to map classes to tables or forms, or how to make it run. Or Delphi, in which most students could write client-server apps by dragging tables, queries, databases and forms right from a toolbar. The entry complexity skyrocketed since then or, more precisely, returned to “serious” levels of heavy C++ setups which only seasoned programmers by trade could manage without pulling hairs. I don’t think that human[ity] will become any significantly smarter in the near future, and that, together with our all time high software demands, means that we will experience a disabling shortage of software developers until we fix our internalized tolerance to the increasing complexity.
- duped 5y agoWhich parts? The points on modules and effect systems are totally in line with creating a shallower learning curve. My reading of his point on formal specifications was that it was important to design software that works as it behaves (like compilers that compile the languages they say they do, paraphrasing). That's not a burden on users of the language directly, more on the creators.
- nostrademons 5y agoMy impression is that programming language design for single-threaded, CPU-based algorithmic programs is basically a solved problem. There's a bunch of innovative ideas sitting around in research projects, but most bare little resemblance to actual pain points of programmers in industry. A more complex, expressive type system is not going to make an average SWE's day job significantly easier. Rather, I think that PL design headroom is largely in new programming domains, including: Distributed systems. Right now, these are cobbled together between single processes written in conventional programming languages; RPC & serialization frameworks; container or cloud orchestration mini-languages; and a lot of proprietary tooling. There's no unified way of expressing "this computation occurs on this box", while abstracting away the details of communication & provisioning and still providing robust handling for debugging and the complex failure modes that distributed systems introduce. Machine-learning. This is handled through frameworks (TensorFlow, PyTorch, JAX) that basically provide EDSLs in a host language, usually Python. But a lot of them would really benefit from language-level support; for example, differentiability is an important concept for SGD, and yet is bolted on with a bunch of kludges in these frameworks. There's also the whole issue of how to store & version training data; how to collect it; how to easily support feature extraction and labeling as part of a developer's workflow; how to run in development vs. production mode; and so on. GPGPU. Your options here are basically CUDA, Futhark, and a few other niche languages. Yet the underlying hardware and computing model is fundamentally different from single-process CPU code, or even multithreaded concurrent CPU code. It seems like there's a lot of headroom by thinking in terms of the operations a GPU provides and then exploring the space of problems that could be solved with that much computing capacity. Smart contracts. Solidity paves the way here, but Solidity is still pretty kludgey, and makes it easy to shoot your foot off in a far more expensive way than C++. A single vulnerability can cost literally billions of dollars, and often in a very public (and permanent) manner. They're also (by default) immutable, so you can't fix bugs after the fact, and introducing mutability to them also often introduces gaping security holes. You have to worry about gas costs, and each computation operation is a lot more expensive than in traditional computer programs. Basically, headroom for improvement in programming languages comes from handling things that are not handled in languages right now, where solutions get cobbled together from a bunch of libraries or custom code. That's how it's always been with product design: the products that most need to exist are those that cover problems where no existing product exists, not ones that are minor improvements on existing products.
- drpixie 5y agoGreat to see this catalogue of language features, thought provoking. The thing that makes a language good (instead of just usable) is how well its various features fit together. All that I can think of, fail with this - their usability damaged by special cases, edges, and forcing the use of various contortions.
- akomtu 5y agoMy guess is that less imperative languages is the future. Today all programming languages are basically about exact instructions what to do: languages differ in exactness and creativity of expressing said exactness, but they all share this idea. The next gen languages will let us tell what we want to get at each step, and such languages will differ in granurality of these steps. A basic example: "a=2; b=5; a>b" means "make sure a is greater than b", which is same as swap(a,b) in imperative languages. I know, some would say "ah, that's prolog!" but I don't believe an esoteric language like prolog can win. It must be something javascrptish, understandable by average programmers, and easily mixable with traditional imperative code.
- deleted 5y ago[deleted]
- valenterry 5y agoI don't think that's gonna happen at any time. And if it does, we have an AI that is as smart as a human, so we will all be out of our jobs. Because, a>b could also mean a should become 6. So you need to understand the intent to decide what you should do. In that sense, it's not even prolog, it's "worse" (read: harder to achieve).
- akomtu 5y agoA better example would be sorting. Most of the time we don't care about how numbers are sorted, we only care about the result. In this hypothetical new language, sorting would look like "input: A1..An. output: for all k, Ak < Ak+1." It's implied somewhere in the constraints of the upper function that it'a a permutation, but if you want to be pedantic, you can add "for all k exists m such that Bk=Am."
- valenterry 5y agoYou are making things more complicated than they currently are. Currently I call "list.sorted" and I get a sorted list. What you propose is essentially what some languages like Idris already offer: general purpose programming with constraints that allow the compiler to generate an implementation, given that the constraints are precise enough.
- DylanSp 5y agoI'm curious about the bit on module systems; I've heard that the MLs have a more powerful system than most languages, but not having used them, I don't know what advantages it provides/what problems it solves. All the explanation of ML-style modules seems rather abstract, focused more on how they work rather than what they're useful for. Can anyone point to some good resources/explanations about what ML modules allow you to do that can't be easily done otherwise?
- andrewflnr 5y agoThis is probably not technically correct, but I tend to think of ML modules as being almost unrelated to modules in other languages. ML modules are closer to being compile-time records than the plain namespaces of almost every other language, with their own sub language for creating and transforming them. I'm not sure they're fully restricted to compile-time, either.
- chombier 5y agoIt may not be exactly what you're looking for, but "The History of Standard ML" published last year has a nice section on ML modules with design considerations.
- lincpa 5y agoDon't try to solve all problems with programming languages The reason why all the questions in this article are too complicated is because they try to solve all the problems in a programming language. If these problems use the correct structure, it is a very simple problem. In my "The Math-based Grand Unified Programming Theory: The Pure Function Pipeline Data Flow with Principle-based Warehouse/Workshop Model", it is based on mathematical model, operational research, and management science, these problems are very simple. - Data is centrally managed by the warehouse - The logic of each workshop is very simple, short, independent, and heterogeneous parallel concurrency is natural - Use the scheduler to achieve global optimization. The Math-based Grand Unified Programming Theory: The Pure Function Pipeline Data Flow with Principle-based Warehouse/Workshop Model https://github.com/linpengcheng/PurefunctionPipelineDataflow https://github.com/linpengcheng/PurefunctionPipelineDataflow
- LAC-Tech 5y agoI like the 1ML idea (unifying records and modules), even if I don't really understand it. I just like the idea of fewer - but more powerful - constructs in a language. The devil on my shoulder is kind of telling me that it's just another example of FP people slowly re-inventing a form of Object Orientation, though. But I think that's a good thing. A rose by any other name...
- pingiun 5y agoZig does this too I believe
- x-shadowban 5y agoThey talk about parametric mutability -- I've always wondered what is the hurdle to const in c++ being like noexcept, parameterizable with a bool?
- gpderetta 5y agoNote that const is already parametric in C++. Template arguments can carry constness in addition to the type itself. Also constness can be queried and added/removed programmatically at compile time. I think the note about C++ was specifically about member functions qualification, where currently it isn't possible to parametrize over const this vs non-const this. The "Deducing This" [1] proposal will hopefully fix this [2] and other issues. [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r6.html http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p084... [2] pun fully intended.
- choeger 5y ago> Engineer syndrome Hah, I've seen that and had no name for it. It's definitely a thing, and an annoying one, when designing a language in committee.
- blippage 5y agoMy own suspicions is that we've taken programming as far as it can go. All the big ideas were in invented in 1980 or earlier: subroutines, libraries, functional programming, automatic garbage collection, etc.. We may have refined some ideas since then, but it seems that we are mostly arguing over what colour the wheel should be. Alan Kay compared out current practises as akin to pyramid building; very little is understood about structural engineering properties of the materials, we just place block on top of block. He argues that there is no programming equivalent of the arch. But suppose that big blocks of stone is all there is. I recall Linus Torvalds talking about one of his proudest achievements. I don't remember specifics, but it was some memory allocator IIRC. All of this was achieved at the microscopic level using C. It's one human sitting down and figuring out exactly what was required to solve the problem, which bits to twiddle, and which bits to leave alone. No shortcuts. I would argue that programming is not like other engineering disciplines. It boils down to this: we can create specific solutions to specific problems, but we can't create specific solutions to general problems. That is to say, we can create programs like spreadsheets, do accounting, model airflow through turbines, whatever you want, because we understand the problem domain, and it is constrained. As to "how do I write my program", well, what program are you trying to write? Compilers cannot reason about the structural integrity of a program. They are general purpose. They do not have any domain knowledge about the type of program you are trying to construct. They can therefore only tell you if a program is syntactically valid, not whether the program is flawed at the domain level. Can we give compilers (or some other near equivalent) domain knowledge? In an exceptionally limited sense, perhaps. I have in mind configuration tools that some microcontroller vendors release. These programs have domain-specific knowledge about how their microcontrollers can, and cannot, be configured and for what purpose. They are extraordinarily constrained in scope. The hard work of actually getting the hardware to do what you want it to do is left up to you. So we shouldn't expect too much out of any domain-specific solution. Their scope is highly limited. We shouldn't expect many to be available. So I'm not expecting much in the way of paradigm shifts in the near future.
- boxed 5y agoThere are some lower hanging fruit in my opinion. You see it when dealing a lot with beginners: - variable names that could automatically rejected as bad "car = Apple()" - general confusion about singular vs plural: "cars = car" Variable names are too important for the computer to be totally oblivious to their meaning, yet this is how all programming languages work.