Six programming languages I’d like to see
buttondown.email
buttondown.email
Ada has design-by-contract as part of the language:
https://learn.adacore.com/courses/intro-to-ada/chapters/cont...
Since Ada is used for safety-critical systems programming you could argue that it is very serious about it.
>> And tool integration! One of the coolest things Eiffel sorta did was use contracts to infer tests. If you have contracts, you can use a fuzzer to get integration tests for free.
How about tools that extend design-by-contract to formal verification?
https://learn.adacore.com/courses/intro-to-spark/chapters/01...
SPARK is limited to a subset of Ada, so it is not without limitations, but it can be very useful depending on what you are trying to do.
Mostly what Ada lacks is not the features but the comunity effect, we saw that when comparing feature parity with C++ and we see that again when comparing feature parity with Rust.
There are a lot of briliant features and tooling in Ada, but unless there is a community effect (or a gigantic industry sponsor e.g. golang) it is difficult to convince people to switch over.
I can't remember who said it so I will paraphrase, the best language/target to program in is whatever your friends/colleagues are using.
Agreed. If there had been more free (gratis) or low-cost Ada compilers at that time Ada would be far less niche than it is today.
There is increased interest in Ada today thanks to Rust. There is also interplay between Rust and Ada/SPARK features with Rust getting some Ada features and SPARK getting some Rust features.
Ferrous Systems is working with AdaCore on the Ferrocene Language Specification to formally document the Rust subset that Ferrocene will use:
https://ferrous-systems.com/ferrocene/
https://ferrous-systems.com/blog/ferrocene-language-specific...
It is exciting to see Rust mature so it can one day be used in safety-critical work.
Didn't they? I wasn't around then, so I'm working with what information I can find online. According to Wikipedia it was fully validated in 1995[1], and I'm pretty sure it was always a free compiler based on GCC. I think the dust had settled on the battlefield of the language wars long before Ada 95. It was/is still common for European universities to teach Ada as part of the computer science curriculum. That still hasn't managed to give Ada the industry presence it deserves. In my opinion it's by far the superior language. It's just losing out for human reasons.
> ...gigantic industry sponsor e.g. golang...
It had the biggest industry sponsor at one stage: The US Department of Defense. Back in the late 70s, and early 80s when the DoD was directly sponsoring Ada's development, they had incredibly deep pockets. I'd say this is why Ada is so comprehensive today. They had the money, and motivation to design the language by committee down to the most minor details.
The same can be said about Eiffel.
(Lots of formal verification languages are based on contracts, like SPARK, Frama-C, and Dafny. I'm interested in uses for contracts that aren't just formal verification, though!)
Ada 2012 design-by-contract features aren't just for formal verification, they can be used in a general purpose way similar to Eiffel:
https://learn.adacore.com/courses/intro-to-ada/chapters/cont...
Can you elaborate a bit more about the wanted features for a language with semantic relations?
What are the consequences of deciding that no Foo's are allowed to be red? Hmm, that's interesting/unintended...
The main difficulties with statically typed languages seem to be both 1) quickly arriving at a workable prototype, and 2) dealing with the consequences of regrettable decisions made early on. Those two being in tension contributes a lot of drama, and not just in analysis paralysis.
[0] https://www.riskdataos.org/html/HelpCenter/Content/CDL/CDL_S...
It's the furthest thing from a "dynamically typed language" but it can probably also check the "math" requirement here too.
https://flang.dev/tutorial/pre_post_conditions https://github.com/tokiwa-software/fuzion
Disclaimer, I work in the Fuzion team.
Maybe that's harder than I can imagine, or it exists and just isn't a very good idea in practice (how would you even do responsive?) so it's not that popular.
VB was a garbage language by modern standards but I always liked that they gave you a visual builder, but didn't try to hide the coding from you too much.
On the web side I bet the right person could do something quite intuitive with CSS Grid though. You could drag out where you wanted various content blocks to appear at different screen sizes and generate a `grid-template-areas` [0] property to match it.
[0]: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-templa...
WinForms satisfies my VB6 craving.
But for network/web service tools, I like that it compiles into a single executable where its internal web server generates the HTML dynamically. It allows me to write small, single focus tools quickly.
I've written a few toy apps in it and in my limited exploration it seems to be a joy to work with, once you get used to Pascal's quirks... and I'm not a fan of the ancient MDI workflow it imposes either.
I also learned to program with VB and Lazarus is the closest thing I've found. The WinForms designer in Visual Studio would be the next closest.
Both GTK and Swing have various GUI designers that are similar, but have their own design and use different layout metaphors. If you're looking for a more modern take on what's left of RAD maybe check them out.
That's why it looks so similar.
I still remember the great VB vs Borland Delphi wars of the 90's.
But feel free to correct me if I'm wrong.
I took a cursory look and I don't think it supports Apple silicon out of the box. Considering that Intel Macs are dead end it't not too encouraging.
This is kind of what WebDev (by PC Soft) does. I worked with it in an enterprise environment. It's nice for internal products, though the code I worked with was old code made by people that didn't have any formal education and not much experience in software engineering.
My favorite part of this was not the GUI, but the deployment part: you click on a few buttons and it just deploys stuff to the server and works. My least favorite part was that sometimes this deployment didn't work and troubleshooting it was long and tedious.
All in all, it wasn't that bad to use, but a big problem is that it's not that well known, so when you look up how to do things, you have the official documentation which isn't great, the forums that are helpful from time to time, or doing it by yourself.
It was no Apple's Cassowary, but so isn't HTML/CSS.
There is a quick demo[4] on the site to show how it works.
Full disclosure: I'm a developer on GuidedTrack. Any feedback is appreciated.
[2]: https://mindease.io/
It never took off because SproutCore turned into Ember and then died, I think, but not before my company had written numerous things in both SC and Ember...
In principle it worked very differently though; as you said, it was mostly a code generator. Atlas was a port of Cocoa's Interface Builder (which uses state/value serialization as opposed to code generation) to the web.
The only reason I would ever use Clojure instead of Racket would be if I needed to work with the JVM ecosystem or the browser via Clojurescript (which are compelling reasons).
Totally agree about a good calculator language.
VB is often scoffed at, and probably to an extend rightfully so.
But those (i.e. VB1 through to VB6) were the ONLY languages that I ever managed to create useful, finished tools and programs in. Maybe it's part psychological, but I needed the approach where I created a neat UI first, got my methods pre-populated for me, and had something tangible to look at early in the process. Then went on to fill it with all with custom code. Yes, it's BASIC, but it was extensible. People I knew wrote OCX and such control elements, and code routines in DLLs in C/C++ and integrated that into VB projects, so the sky was still the limit.
Staring at an empty text document with possibly some header file statements never evoked the same creativity with me that VB did.
p.s. my proudest creation was a Windows 3.1 UI around the MS-DOS packing program "arj", for those who remember. Had I been a better businessman, that might have predated WinZip :)
1. 1 mildly technical, mostly business-domain person, a spreadsheet + auto-clickers
2. 1.5 persons still only mildly technical and mostly business-domain-y, a VB gui and some basic network integration
3. [some time and quite a bit of revenue passes]
4. they hire some java programmers to rewrite it properly in Swing, since the VB versions had literally become impossible to modify without breaking (there were forked versions where you used version A for some feature, version B for another, version C for another - and people had tried to merge them together while keeping the whole thing working, but never managed it).
It's now been, oh, over a decade I suppose, and while I understand that there are currently some efforts underway to port the java applications to an SPA web app, it's more because the owner wants to get rid of java (and only have to hire python devs) than because the apps don't work or are hard to maintain.
My point is that without VB, the company probably wouldn't have existed to even need the Swing rewrite. So while I personally find VB to be quite caustic to my senses, I cannot deny its ability to create business value, especially because it's so approachable only mildly-technical folks.
Have you tried Delphi?
https://en.wikipedia.org/wiki/Delphi_(software)
- my experience was in the 90s, but it has a similar ‘quickly build native Windows UI programs’ feel to it.
It already offers plugin controls that work with the builder or just code.
Can deliver native local apps, websites, webapps, iOS and Android apps, etc.
Database controls like in VB and Delphi - and much more to come.
It is programmed in and with Common Lisp, however you can easily program events in JavaScript and Python coming soon too.
What happened was that I lost interest in creating that kind of thing. And the business decided that such programs have to go through a formal approval and release process, so it left me with no advantage over letting the software department maintain that stuff at considerably greater expense. Today, I'm willing to burden my users with stuff that requires a bit more care and feeding on their part, such as plain Python scripts. Also, VB turned into VB-dot-net.
I'm equally creative in C, but on the embedded side. Something about working within severe limitations. I'm reminded of a quote from Richard Feynman: “The game I play is a very interesting one, it’s imagination in a tight straitjacket.”
Visual Go, Visual Rust, Visual Nim and Visual Crystal, where are you?
I developed in an odd Language…LabVIEW…and I get what you’re talking about with first class GUI support and being able to see something each step along the way.
Myself and a lot of kids probably grew up on VB. I was one of those annoying kids writing AOL 3.0 'progs.' I don't think I've ever had as much fun coding as those days, but that's probably due to age and community moreso than VB's greatness.
I don't know why people would scoff at BASIC, tons of people make their careers writing Python, which is 100% going to be regarded as the BASIC of 201X-202X.
One of the truely great things about the drag and drop form builder was being able to sit with a user and go through requirements with them, to wire it all up later.
"Ok, so when you type in the customers details, we should have a button to save them into the database. Will we put it here?"
And this all still works today in VS 2022.
My impression is VB is a language sucks but VB the entire package (forms, form editor, IDE, etc) was pretty awesome.
So the arguably a similar IDE with a better language would be a huge win.
The weirdest thing (I have ever seen in software): Once VB.net hit, all VB devs quit. VB.net was a totally different language. I guess we all moved on.
Delphi and friends[1] is still out there. There's also Lazarus[2] if you don't want to fork off a few grands.
[1] https://www.embarcadero.com/products [2] https://www.lazarus-ide.org/
JavaFX has SceneBuilder[2] which also fit the description but for some reason, it never caught on. Gluon seems to have that work not only on desktop, but also on mobile.
[1] https://docs.flutter.dev/development/tools/devtools/overview
Still, there's a lot of things that would be more useful with such a language. In-memory highly-correct cache invalidation would become trivial code to write. In fact I think the cache would actually update itself live. Out-of-memory cache invalidation might be pretty easy. Certain auditing things would be easy. UIs would probably take some work to get right but would be interesting, at the very least. Game programming would also be interesting; a lot of game patterns would be incorporated into the language at that point.
Probably need to be lazy; I suspect proactively recalculating everything all the time would be a bad idea. Haskell has pushed lazy programming a long way, but "re-thunkifying" a previously calculated cell would be a new frontier.
Come to think of it, while I think the performance could be improved and you'd want to lift up to a full language eventually, I think a good Haskell programmer could bash together a prototype of this in a few days and start playing with it. It's going to need a lot of playing with before someone casts it into concrete as a language specification and corresponding compiler and runtime.
My language turns out to be very fun to write UIs and games in, so I'm glad you honed in on those two examples. Actually one way to view it is that it's a programming language with a game engine as a runtime. But robotics is the primary application I'm targeting.
In fact I had to choose between lazy and eager evaluation, and I've chosen eager because I want latency guarantees. With a lazy evaluation scheme, I was unsatisfied with the windup that would occur in some situations that would totally blow performance. And we don't have to recalculate everything all the time; we only have to recalculate the paths that have an input change. This may lead to recalculating everything, but most of the time we only have to focus on the execution path that is "dirtied" by the updated input.
Anyway if you want to test drive such a language as you're imagining, send me an email and I'll give you a tour/demo. The language isn't really user-friendly yet so there are some pointy edges that make it unusable to new users at this time (which is the main reason I don't want more attention on it until that is resolved.)
https://github.com/kennytilton/cells
and he has slides from a talk
https://github.com/kennytilton/cells/blob/main/Lisp-NYC-2018...
to give context.
$: b = a + 1
Since it's a compiler, it knows what inputs were used in that statement, and what outputs were mutated. The statement is re-run every time its inputs change.This is then used to make a web development environment where "react to input changing" is much more natural than with e.g. React.
https://powerapps.microsoft.com/en-us/blog/power-fx-open-sou...
https://github.com/microsoft/power-fx-host-samples/tree/main...
#!&/@l
It has the same "everything is a list" problem - it's really verbose at handling strings, for example, and last I checked its date-time handling was not only verbose but also [flat-out wrong](https://mathematica.stackexchange.com/q/239480/30771). But it does support the dynamism mentioned immediately below, if you use `SetDelayed` (`:=`) rather than `Set` (`=`).To be clear, I like PHP. It actually has many attributes that make it almost ideal as a Web development language, most notably:
1. Pretty much everything is request-scoped. This makes it a lot harder to leak resources when everything is torn down;
2. A stateless functional core. This avoids a lot of class loading that has dogged Java (as one example);
3. No ability to start threads. This is actually a positive. Most application code should avoid creating threads like the plague.
But PHP comes with a lot historical cruft. It's type system is also primitive (Hack is a better example of this).
Where I think this could really shine is in data analysis (ie the numpy/scipy realm).
As for the type system, haven't worked Hack but I absolutely love the gradual typing experience that PHP offers. Yeah, we had some things that could not be expressed but they are slowly being added, again we have finally union types!
I would even say PHP might be the only mainstream language that offers a first class gradual typing experience.
In Python your type hints are a lie as they are not enforced at all and different linter will give you different results and there is no standard.
In JS, you have to use a whole other languages that compiles down to it, slowing you down with an extra compile step.
Meanwhile PHP just works. Just use PHPstan for linting but even if you don't you get at least runtime checks.
I don't know if it's changed recently but that's something I really appreciated when I wrote PHP: it was unabashedly singular in it's purpose as a web scripting language. The source article talked about VB6 as being a language where the GUI was a first class thing; for PHP the only focus was on making applications around web requests. No useless bloat while trying to be a general purpose shell scripting language; no delusions of grandeur of trying to be an enterprise business logic tier language... it did it's one task, did it well, and left other languages to other tasks. I think we would be better served to have languages will small standard libraries focuses on specific tasks rather than gigantic one-language-to-do-everything but about which nobody could possibly know everything (ahem C# ahem).
I write PHP every day (just took a break from that to be here) and the request scoped content is both a nice thing and a pain in the ass some times. It's great that each request is on it's own - really handy for cleanup like you mentioned. There are some thing I want to be shared though, like a DB connection pool, a caching layer (one layer below my Redis layer), and clients for various other services.
Not the end of the world, but an example is AWS Secrets Manager libraries for Python support secrets caching, but they can't offer that in PHP since we won't be able to share the objects. You can use the file system, but that comes with its own hosts of quirks.
That said, PHP really is a fine language. I'm personally not a fan of the use of truthy/falsy values, but they've really dove head first into solid type support. Lot's of good progress has been made with it.
You also want to look at Dafny for a contract-based language: https://github.com/dafny-lang/dafny
Since it has verification support it also covers the second point about semantic relations.
…have to poke around a bit methinks.
In Shen, the contract rules applied on each function are themselves a Turing complete language::
https://thestrangeloop.com/2014/shen-a-sufficiently-advanced...
"static type checking based on sequent calculus"
"one of the most powerful systems for typing in functional programming"
Shein never became a serious language. It's highest point was when @deech made a talk about it and it also promoted their klambda but it had constant problems on every single aspect of the system and the design, from code size expanded as macros to unusable APIs due inconsistent design of libraries and features the author collected from everywhere. I even bought the book and felt deceived after it's unsuitability for anything other than academic examples on how to implement itself.
> window2 is an optimized version of window1 and should have the same outputs for every input. I should be able to encode that in the language, and have the tooling generate checks showing the two are the same, and also run benchmarks testing if the optimized version actually is faster.
That should be possible with Joy, it's certainly something I want to explore. The interesting semantic relationships are those that let the machine automatically deduce optimizations
> I also like the idea of modifying function definitions at runtime. I have these visions/nightmares of programs that take other programs as input and then let me run experiments on how the program behaves under certain changes to the source code. I want to write metaprograms dammit
Lotta metaprogramming in Joy. Many functions work by building new functions and running them, it's a natural idiom in Joy.
- - - -
> A language designed around having first-class GUI support
Red? ( https://www.red-lang.org/ )
> Visual Interface Dialect ... is a dialect of Red, providing the simplest possible way to specify graphic components with their properties, layouts and even event handlers. VID code is compiled at runtime to a tree of faces suitable for displaying.
https://github.com/red/docs/blob/master/en/gui.adoc
> You can’t work with strings, json, sets, or hash maps very well, date manipulation is terrible, you can barely do combinatorics problems, etc etc etc. I want a language that’s terse for everything.
That also sounds like Red.
If Alan Kay had got microprocessor companies to steal the Xerox microcode design like they got Apple to steal the GUI design, then the genius compiler engineers optimized the the heck out of it all.
I can only shudder at what the supercomputer in my pocket would be capable of.
Lisps are not the God-languages.
Technically, the runtime is the easy part (relatively speaking). Modelling an array of swimlanes on a plain-text 2D page is the real challenge here IMO.
Raku, previously known as Perl6, has this[1].
sub MAIN(Int $a, Int $b where 10 < $a < $b > 20) { say "OK: $a $b"; }
You can also pull out the "Where" clause to ouside the function and make it define a new type.
Raku is a very awesome language in general, for more reasons than one.
[1] https://andrewshitov.com/2020/08/14/the-pearls-of-raku-issue...
In retrospective it is funny how everybody implicitly assumes that the next big thing will be yet another programming language. And I am not talking about no-code or AI code synthesis.
My point is just because you use a sequence-based input method (a programming language) doesn't mean you can't express structured data.
For example jq[1] does a decent job of expressing queries and transformations on JSON (JSON data are trees rather than arbitrary graphs). But trees are a very important type of graph, and I think a language with first-class support for trees would be in a better position to handle arbitrary graphs than a typical programming language.
The actual sequential thing is consequence of states s0, s1, etc and the only deviation form sequence would be another timeline or state that did not produce.
Especially with reactive programming as an ask there, I would recommend Julia with Pluto.jl (Pluto is a reactive notebook).
> A really dynamically-typed language
Julia ;) It is really dynamic, has meta-programming (macros + staged functions), solid semantics around eval/invokelatest that still allow for optimizations and you can add types at runtime (not modify them though).
It's true that Racket unit tests are an optional module within the standard library, but the command line tools and package system work directly with it. You can place unit tests right alongside the regular code but within a specially-named "test" submodule, so the unit test code doesn't run at runtime by default, except in certain contexts (package installation, "raco test" command, or running the file from within the Racket IDE).
you can create comments above methods that act as tests
It would also be nice to have system-level contracts. Like, say, "every item in list X should have an entry in dictionary Y". Or "no button should be located outside the visible viewport". These are the sorts of things that people procedurally unit test, but expressed in a declarative way you can imagine all sorts of tooling.
This could theoretically be added to other languages with libraries (with varying elegance depending on the language), but a real first class language would be carefully designed so that everything is serializable and deserializable with excellent performance. Things that fundamentally are state like network connections would also have to be carefully handled in some way where their essence was persisted such that the program could restore them and rebuild their state.
This would pretty much give you an ORM without the impedance mismatch and would eliminate a TON of "CRUD" code and boilerplate.
It's defunct now, but it was indeed a Turing-complete SQL (but actually relational) with Prolog-like syntax and set semantics. We supported persisting data, and indeed you could think of it as programming within a database. Even though it's not worked on anymore, the last version in the repo worked pretty well IMO. I built a Spotify clone, and even a robot in the language. If you're interested in these ideas, you should give it a shot! Hopefully someone will pick up these ideas and run with them even further.
It's a pretty mind-bending experience to program this way, and I promise you'll have a new perspective on programming as a practice once you grok it (that was common feedback from our users).
That's a pretty weird way to do math, honestly. Shouldn't you figure out what equation you need and then just type it? If you're off by one or whatever, adjust it then, you're still only typing it twice.
I found that for much of my code it really separated the “where to next” from the “what to do”. And I became acutely aware of how many of the statements in other languages are more about “where does the code go next” and less about getting stuff down.
Prolog does, but more intriguingly, so does Nix!
from math import *
prod(map(factorial, l))
which isn't much longer than his J code especially if you count the number of tokens rather than the number of characters as the J code uses ridiculously terse names.I bet that changes eventually when we reinvent personal computing again (currently we are reinventing mainframes).
I've been working on an extremely dynamic programming language for a while. Ricing away on the syntax to make it as flexible as possible, whilst maintaining readability.
One of the things that already works is some insane metaprogramming. It doesn't really have functions. It has callable lists of things. Which means you can modify them at runtime (still working on the names for the functions for doing that).
It is stack-based, so it's a little quirky, but as a taste of some very simple meta-programming:
block
varname:
add! 1 $ $varname
: $varname
end
inc-env:
a: 1
inc-env! a
Bare-words are a symbol-type. So they only resolve from the environment when you ask for it with the $ instruction, which is how the above works. A little tedious, but does enable all kinds of dynamism.Dependent types and things like that are probably great. Being able to prove correctness is great. But I would settle for a way to declaratively express invariants and then let the language for the most part take care of inserting checks (in debug or using a special mode perhaps, or all the time) and generating tests/property tests. Why isn’t this more of a thing?
Because that's a half-assed way of using and leveraging a good type system? DBC always strikes me as a "three blind men and a type system worth using" parable.
v M ! v R *
Where the v may be capitalised if you like and the spaces are the way the commands are written but aren’t typed. That decomposes into some easy mnemonics: Vector Map factorial, Vector Reduce multiplication.It has a bunch of mathematical features, a quick interface for plotting simple graphs (with gnuplot), some symbolic algebra, and it sort-of has the reactive feature too. (I think there’s also a mode for using it in files).
Date handling is ok but simple (a date/time is internally represented as a Julian day so if you add 1 to a date/time you get the next day; times go into the fractional part. Leap seconds / time zones aren’t handled. There is an option to configure when your calendar switched from Julian to Gregorian.
It’s usually fast enough for what I use it for but it can be limited by performance.
Edit: I tried using J and the install was pretty large iirc and the whole language is just too big and complicated. I know you can do cool stuff with it, but it just seemed to me that the cost was too high relative to benefit. Your mileage may vary.
input = 1
out1: input + 1
#out1 is now 2
input = 4
#out1 is now 5
out2: out1.replace(+, -)
#out2 is now 3
# let's pull an APL
input = 4 2
#out1 is 5 3
#out2 is 3 1
The reactive programming idea a la Excel but text-based looks really neat. I'd love to play around with that kind of thing.https://docs.microsoft.com/en-us/power-platform/power-fx/ove...
Lua is based around tables, which, aren’t quite graphs but seem relatively close enough. What is a graph if not a collection of points associated with their edges?
As far as semantic function relations, I could swear Ada has something like this, but it’s been more than a decade since I’ve touched any.
Not ambitious enough. We already have dependent type systems and what I will call “property based types” since I forget the proper name e.g. https://ucsd-progsys.github.io/liquidhaskell-blog/.
The compiler can check anything from silly out of bounds conditions to more complex assertions.
Even without that, a good type system will allow you to alias types but have a constructor do a check. Once you use the Percentage0_100 type you know that it must be in that range, and the method doesn’t need to check it again.
In think Haskell is “too much” for a lot of teams, but sprinkling in some compile time assertions and making that ergonomic with linting and so on would be a boon on par with async/await.
“Unit test?” no need, I have a proof!
Contracts? how they're different or less verbose than plain asserts? what they do better?
"reactive programming"? if remove that strange code editing "replace", just a chain of definitions instead of variables in, say, ruby, gives you basically the same effect.
etc.
What I'd love to see is a language with a first class grammars to replace many uses of regexes or badly written DSL's, like what Perl6 tried to do.
and, somewhat related (both are using backtracking), adoption of some of the ideas of https://en.wikipedia.org/wiki/Icon_(programming_language), not on a whole language level, but in some scoped generator context would be nice for some tasks I had to do.
The use-case was to abstract away having to manually figure out where to put caches and how to invalidate them on front-end servers. Rather, have the runtime figure out how to cache content and page fragments when e.g. rendering the Facebook timeline. However, it was too difficult to bridge the gap to the existing Hack codebase, iirc in particular to the entity system used. There were also a lot of headaches trying to figure out how to power the underlying cache invalidation system.
https://www.youtube.com/watch?v=AGkSHE15BSs
https://web.archive.org/web/20200219222902/http://skiplang.c...
The author I think means something slightly different though, closer to prologue where you define facts and then ask the runtime to make an inference about those facts.
How do you turn asserts into generative tests, or assign blame? Clojure's spec has support the former (https://clojure.org/guides/spec#_generators), racket's contracts have support for the latter (https://www2.ccs.neu.edu/racket/pubs/popl11-dfff.pdf). Also, many popular languages have a pretty broken assert statement (C, C++, python come to mind) which conflates optimization levels or/debugging with assertion support. Rust gets this right.
> What I'd love to see is a language with a first class grammars to replace many uses of regexes or badly written DSL's, like what Perl6 tried to do.
Lua sort of does this with LPeg. There's also https://rosie-lang.org/, which is more special-purpose.
Regarding first-class grammars you have to understand that it basically prohibits any other tool to parse your language. This means everyone has to fully implement the language to create any kind of small helper tool. In turn, your language might easily fall into the "exotic" camp (like, e.g., TeX - this language effectively has first-class grammars, albeit at a low level).
The difference to asserts is that they express a property over to points in the execution of a program, whereas an assert only states a property of one point in the execution in the program. Practically, that means that you can refer to the state before some code in addition to the state after in the post-condition of that code.
Xerox' original XRCE (Research Centre Europe) pages are gone, but other sites offer a glimpse, and FOMA is an open source implementation of the same language:
[1] https://sites.google.com/a/utcompling.com/icl-f11/home/xfst-...
Recently I've been tinkering with an indie Clojure-like Lisp called Janet. It implements Parsing Expression Grammars as a core library module: https://janet-lang.org/docs/peg.html
If you write tests now, the extra notations SPARK introduce aren't much more code than you're already writing, and really it's just entering into the code what you (hopefully) have in your head or on paper elsewhere.
Classes ARE functions. Conceptually, they are closures with some automatically generated features and language semantics.
https://www.youtube.com/watch?v=mrY6xrWp3Gs
Classical inheritance is BAD and you wouldn't want that kind of relationship for functions. Ofc, what the article suggests is basically assertions - why execute code once, when you can do it twice!?
Modern languages should have function signatures. After I write tests (a full testing framework should also be native to a language), being able to get a function signature which ensures a pairing with a specific set of tests would be great. No more side effects added in without breaking tests, ensuring you would have to make a test change, even if it's introducing some new side effect that doesn't break an existing test.
There is recent research in this area.
Why not parser combinators as a library? The language has to be sufficiently advanced to allow that, but many are these days. E.g. F# has FParsec.
input = 1
out1: input + 1
#out1 is now 2
input = 4
#out1 is now 5
out2: out1.replace(+, -)
#out2 is now 3
# let's pull an APL
input = 4 2
#out1 is 5 3
#out2 is 3 1
Not quite as sleek syntax, but in APL with my Lazy library[1] input ← 1
]lazy out1 ← input + 1
out1
2
input ← 4
out1
5
⎕FX'out1' '\+'⎕R'out2' '-'⎕NR'out1'
out2
3
input ← 4 2
out1
5 3
out2
3 1
[1] https://github.com/abrudz/LazyCopyright would be handled using a block chain so every commit's author would be publicly visible to users of the library.
The "source code" would be stored as a call-flow graph and perhaps nodes would have different permissions to sandbox the effect of untrusted contributors changes.
I think you might not want a blockchain: what you need is a merkle tree, which is basically what backs both git and blockchain
The type-system and forced spec/implementation split both work well to catch errors; you can go further with SPARK [proving] and using Pre- and Post-conditions, type-invariants.
The author says:
> Give me a language where key-value maps are emulated with directed bipartite graphs
So this means you can't define graphs using key-value dictionaries (like Smalltalk or Javascript with their objects primitives). So how exactly are these graphs defined? RDF format?
Something I've found while trying to design languages is that the hardest part is running into contradictions and circular logic. And I feel this "everything is a graph" idea will very quickly run into this issue.
Nevertheless, Lisp is still a very useful primitive for understanding computation, because the means of combination of these primitives are all themselves represented with Lisps. That makes for a very succinct definition for the rules that define computation, because there are fewer special cases to handle. Likewise, it makes it easy to write program-manipulating-programs, because there are fewer special cases to handle.
In theory a graph-based language could have similar benefits. Most compilers already represent programs as graphs internally: there are call graphs, control flow graphs, data flow graphs, type graphs, etc. You could imagine a language that tries to make graph construction & manipulation very succinct, and then see how far it gets you. Sure, at some point you have to implement on real hardware, but you can hide the actual implementation, just like the sophisticated compiler techniques used to transform lists into efficient machine code are hidden from a Lisp programmer who just wants to write some macros.
With "everything is a graph", all your operators would expect to consume and produce graphs. So you'd have operators for parent/sibling relationships, operators for various kinds of traversals, extracting graph shape information to build higher-level operators like subgraph isomorphism (or maybe that would be a built-in operator).
Actually, the universal 'cons' cell data type of LISP (which is used to build lists) allows to represent graphs. Take, for example, Common Lisp. There are read-macros which make this possible: The expression #1=(hello . #1#) builds a circular list that only contains the symbol "hello" [1]. This example can be extended to build graphs.
[1]: https://letoverlambda.com/index.cl/guest/chap3.html#sec_5
Some languages though have contracts as a library, but that library uses tools of the language, to actually change the language. Languages with capable macro systems! Just because something is a library, that does not mean, that it will not integrate into the language, even beyond a library function level. In language with a capable macro system, one can create new keywords and forms, which are just as much part of the language, as predefined things. It allows to create ones "affordances". With all the interest in language features, I am surprised, that this was overlooked.
The post inspired me to try myself at creating a macro in Scheme / GNU Guile, which implements the "requires" and "ensures" idea, although evaluating at runtime: https://notabug.org/ZelphirKaltstahl/guile-examples/src/d749...
The withdraw example would look something like
impl Account {
#[requires(amount <= self.balance)]
#[ensures(self.balance >= 0)]
pub fn withdraw(&mut self, amount: uint) { ... }
}
and Prusti has a good story for going from this to larger proofs.I can imagine it being Materialize who build this first but in my heart of hearts I’d love it not to be SQL.
It would probably make more sense than HCL or Pulumi.
Agents based language are close in theory but they are really targeted at specific simulation and not at explaining what went wrong.
It would also make it easier to do partial application and resumption of it. And probably make constraints for security easier.
Probably make composition of infra level work easier too.
I'm glad to see there's someone else out there who think's it's useful.
CL-USER> (defvar i 1)
I
CL-USER> (declaim (type (integer 1 10) i))
(I)
CL-USER> i
1
CL-USER> (setf i 8)
8
CL-USER> i
8
CL-USER> (setf i (1+ i))
9
CL-USER> (setf i (1+ i))
10
CL-USER> (setf i (1+ i))
; Evaluation aborted on #<TYPE-ERROR expected-type: (INTEGER 1 10) datum: 11>.
CL-USER> i
10 #pragma strict_types
void main()
{
int(1..10) i = 3;
i += 7;
i += 1;
write("%O\n", i);
i = 11;
}
output: typetest.pike:6: Warning: An expression of type int cannot be assigned to a variable of type int(1..10).
typetest.pike:8:Bad type in assignment.
typetest.pike:8:Expected: int(1..10).
typetest.pike:8:Got : int(11..11).
Pike: Failed to compile script.Edit: I've posted this same comment in multiple places in this conversation to get feedback from specific commenters, not as spam (it's a old personal project)
In other words, a step-by-step learning process from simple to hard, maybe 2-4 levels, and you never have to throw away what you already learned and start over, when going to the next step.
* There is just a few primitive node types (Class, Method, Attribute, Relationship, GUI Bucket) with the rest of the system being derived off of that.
* Underneath is a replaceable layer of java (+js/html for UI).
* Still not sure if it's quite front or back end code, as it contains business logic, GUI info, and largely runs on the server.
* Back end improvements happen automatically and system wide. The limiting nature of the graph ensures minimal regressions.
* Most of the SKU product code is contained within this graph, making for definable relationships between any part of the code.
* Internal languages mean lots of internal tools that enable better management of the graph.
I really like the idea of zx, but still doesn't look clean enough to me.
> A serious take on a contract-based language
As the article itself notes Clojure does support contracts in the language and with libraries. But there has been a ton of research about that, e.g. JML [1].
> A language with semantic relations
They can be expressed in contracts (e.g. Clojure) or with property-based test frameworks (e.g. Haskell, Clojure, and many others nowayday).
> Everything is a Graph
See graph rewriting, e.g. [2]. That was just my first google hit with the proper search term.
> A better calculator language
That idea looks to me like automatic transformation from offline to online algorithms [3]. I am not aware of any compilers being able to do that. But dataflow graphs can be used to design such systems. A list of such languages or libraries (e.g. for Clojure) can be found in this Stackoverflow article [4]
> A really dynamically-typed language
As some other answers here already mentioned modern static type systems are able to express, new types at runtime, e.g. with Scala's path dependent types. Again Clojure has an interesting entry here: clojure.spec [5], a runtime represented specification language, which can be used together with contracts or to formulate proeprty-based tests, or anything else you would like to do with it.
Btw, I've only toyed with Clojure so far and I used to be an avid proponent of Haskell/ML-style static type systems.
[1]: https://www.cs.ucf.edu/~leavens/JML/index.shtml
[2]: https://link.springer.com/chapter/10.1007/978-3-642-32211-2_...
[3]: https://en.wikipedia.org/wiki/Online_algorithm
[4]: https://stackoverflow.com/questions/461796/dataflow-programm...
Frink (https://frinklang.org/) has been around for ages, and is rooted in physical unit conversions
Calca (http://calca.io/) has come up a handful of times. It looks pretty reasonable
R, if that's your flavor
Anything with a REPL. Though the OP suggests these are cumbersome, I'd counter argue that anything you know well is usually more efficient than learning something new.
A very long list of commercial tools: Matlab, Mathematica, WolframAlpha, STS, SAS, etc
Spending the last 6 years writing Clojure has been great. That said, the parens don’t add positively to the experience. They feel like semicolons in C - “the compiler is too dumb to understand this so I have to help it.”
I have only wrote LISP code during uni and on pet projects and I always feel like the parentheses are making things easier to visually process. The AST is explicit and basically just before my eyes, and it looks nice because of the functional style.
Fair to mention dart (flutter) in VSCode has a refactoring option which removes, adds and modifies all widgets but it falls short in comparison to lisp.
This is a cool idea especially around a formal structure to express relationships between parts of your code. As to the example in the article on this, it seems property based testing is a decent way to achieve something like this with existing languages.
A simple example of a property based test for a `const add = (a, b) => a + b` function would be that the result of the invocation is always larger than the arguments IE
expect(add(a, b)).toBeGreaterThan(a);
expect(add(a, b)).toBeGreaterThan(b);
And then you can randomly generate or fuzz the values for a and b but the test should always passMe too. But there is something nice on Linux called GAMBAS: http://gambas.sourceforge.net/en/main.html
In other words, a step-by-step developer growth process from simple to hard, maybe 2-4 levels, and you never have to throw away what you already learned and start over, when going to the next step.
You can also do explicit memory management, which of course takes more programmer effort.
It turns out most programs wind up using a mix of the two, as GC is better for some things, and explicit is better for others.
And it's fast, enjoyable and productive
And for the first-class GUI support, in its own way too, but also Swift in XCode is very very good.
And it's because I haven't thought yet about how to do static type checking with such a feature.
I haven't got any time to work on it in the past few weeks, and I'm the only dev (would really love some help). So, it will be ready when it will be ready :P
I've been playing around with it and find it can really simplify a lot of code.
normal assignment:
var : expression
view:
var :: expression
Using a dynamic web tooling product at the moment, and at first I was enthusiastic, but it's crippled compared to VB6
Basically, a formalization of Dagger/Guice into a language.
An approach to do it statically is with implicit parameters. Scala has them, for example.
https://itnext.io/hmock-first-rate-mocks-in-haskell-e59d7c3b...
vector = array [1..25] of real; real :: vector(-2:5)
declares an 8-element array with bounds -2 and 5.See Calca: http://calca.io
And it still gives you the image editing tools (pixel editing for MakeCode), asset management, game loop, etc – all of which are too much to take on for a new programmer, but are really helpful, and hopefully make it feel like less of a regression.
The R and Julia syntax are better than Python for vectorized operations, although NumPy and Pandas mostly make up for it using the magic methods.
In terms of keystroke efficiency, nothing beats the array languages. One might think APL is a little too terse, whereas Pandas is a little on the verbose side.
E.g. contracts language could mean better understanding of substructural stuff so we can handle "real resources". But coming up with some syntax for this is the last step.
Definitely qt, right? https://www.qt.io/
And HTML/CSS :downtrodden-developer-with-woozy-face:
Well there are many of them like MATLAB, IDL, scilab, R and others. Python is verbose because it's not a calculator language but a general purpose language. I find J unreadable.
The great thing about R is that it scales well with task difficulty. It works well for a couple numbers. Then you can use data frames, and the Tidyverse (https://www.tidyverse.org/) packages to do a lot of data analysis (especially dplyr, which is extremely powerful). Finally, if you want to look at your data, the built-in plotting capabilities are solid, and ggplot2 is both extremely powerful and reasonably easy to use.
> import math prod([math.factorial(x) for x in l]) No! Bad python! In J it’s just / ! l, quite literally an order of magnitude fewer keystrokes.
I don't know anything about `match.factorial()` or `prod()` but I can deduce what it's doing. `/ ! l` is nonsense.
I thought linked lists were one of the easier data structures to implement? Is he saying they're annoying to use or implement here?
Unless you are a Rustacean…
https://blog.adacore.com/i-cant-believe-that-i-can-prove-tha...
HN discussion: https://news.ycombinator.com/item?id=31975507
This is sort of an odd thing to want. You need a diversity of data structures. And BTW the acronym not withstanding, lisp represents graphs not lists.
Linked lists, trees, and heaps are all just graphs with certain requirements about their structure.
Everything else can be represented as a graph, just not as elegantly.
Also as a data point, I really really wish there was an everything is a graph language. I work in graphs all day (in the private industry) and I have to keep modeling them as arrays. It's a pain.
This already exists: programming languages that supports refinement types. Examples are Liquid Haskell and F* (F-star).
Additionally, Kernel has dynamic binding built-in, and done in a nice way. You never explicitly access a dynamic variable but you only have an accessor function to it. A new scope is created when binding a dynamic variable, and the accessor will return whatever was bound anywhere in the dynamic extent of this scope.
($define! (with-str get-str) (make-keyed-dynamic-variable))
($define! f
($lambda ()
(print (get-str))))
(with-str "Hello, world!"
($lambda ()
(f)
(with-str "Goodbye, world!" f)
(f)))
Prints "Hello, world!" "Goodbye, world!" "Hello, world!"Perhaps the only downside to this is that a runtime error will be raised if `get-str` is called before a value is bound. I think it would be a bit nicer to include a default binding as an argument to the call of `make-keyed-dynamic-variable`.
Haskell and lenses is pretty nice here.
Svelte (javascript framework) has reactivity build in.
- Idris (dependent types rather than contracts, but squint and the UX is the same) - Python's decorators enable some of this, but Aspect oriented programming may also be what they are looking for. Boomerang is totally different but also an exploration in this space. - Io, or even JavaScript fit this description - there's a calculator like this I am forgetting the name of at the moment - this looks like Dependent typing to me, see Idris above
For a fully dynamic scripting language, look no further than Python.
Function inheritance? We have decorators in Python already, and most functional languages support seamless function composition. Take your pick between Haskell, Lisp, Scala and even Rust.
Designing a new languages needs to have a pragmatic purpose and sometimes, valid ideology.
IIRC Objective-C can bind new methods at runtime
Nearly all common languages like Python, JS, Java, OCaml, etc. let you express graphs with records / objects. Everything is a graph!
If you want a homogeneous graph, you just declare a single node type, like
class Node:
edges: List[Node] # or maybe Dict[str, Node] if you want them to be named
payload: int
- Or you can have a heterogeneous graph with many different node types.- If you want to label the edges, you can reify them as their own type
The whole heap is graph-shaped!
It's true that many programs in these languages are more tree-like than graph-like. And sometimes imperative code to manipulate graphs is hard to visualize.
But I think there doesn’t need to be a separate language of graphs for this reason.
---
If you want to see graphs done in plain C, look at this DFA code by Russ Cox:
https://swtch.com/~rsc/regexp/regexp1.html
e.g. Implementation: Compiling to NFA
(copy of lobste.rs comment)
A graph isn't defined as a list of nodes. A list is defined as a directed graph where each node has one vertex in each direction.
There needs to be a J# project lmao
Meta
We could express this as an adjacency list like
Graph{
1 <-> 2
1 <-> 5
2 <-> 3
2 <-> 5
3 <-> 4
4 <-> 5
4 <-> 6
}
So there's already a lot of repetition of the node labels, but in real life applications you would probably have actual data associated with each node (like maybe a user_id, or a name, etc, whatever the "elements" of your graph are). Actually, you would in most cases have some key that identifies the node (like user_id), and some other data associated with the node (like date of birth, locale, etc). So the above notation would force some kind of notation like: ("user1", (1970, USA)) <-> ("user2", (1980, UK))
("user1", (1970, USA)) <-> ("user5", (1990, RU))
...
So now the notation would require not only repetition of the node name, but also the data itself. This would be even more of a problem if the data was not a literal but was computed, like:
("user2", (getDateOfBirth("user2"), getLocale("user2"))So then the way around this would be to use the programming language's own variable/identifier system, like
var user1 = ("user1", (1970, USA))
var user2 = ("user2", (1980, UK))
var user5 = ("user5", (1990, RU))
Graph{
user1 <-> user2,
user1 <-> user5,
...
}
or perhaps some other node registration system, and then just repeat the labels Graph{
Nodes {
("user1", (1970, USA)),
("user2", (1980, UK)),
("user5", (1990, RU)),
...
}
Edges {
"user1" <-> "user2",
"user1" <-> "user5",
...
}
}
So now we've avoided repeating data, but we still have to repeat nodes. In some situations, a different way of expressing a graph would also be preferable to adjacency lists (you might want an adjacency table, but in sparse graphs the list is more efficient)but by the way, for your graph system to be generally useful, you'll have to come up with a syntax and flexibility of design that ergonomically allows graphs that vary in:
directedness: support for undirected and directed edges edge wights and data: edges could be identical or they could have weights or even keys and other attributes associated with them
graph/multigraph: can there be multiple edges between the same 2 nodes?
in statically typed languages, the data type of the "key" of the nodes, the "value" of the nodes, the "key", "value" of the edges, all have to be represented to some degree in the language's type system, so at least 4 generic parameters in a graph
So, seems that there is just a huge design space and a variety of different usecases that makes coming up with a simple solution to the general problem very difficult.
Edit: I've posted this same comment in multiple places in this conversation to get feedback from specific commenters, not as spam (it's a old personal project)
He wants contracts which is basically dependent types. These rules live in types and already exists in agda, Idris and coq and has a range of tradeoffs.
Essentially these languages can enforce static checks and "contracts" so powerful you don't need unit tests. These "contracts" cover more ground and are safer then tests. The tradeoff is you need a big brain and lots of time to write these things.
Then he wants a language that is truly dynamic. Which is like the opposite.