Isn’t Red the logical successor of REBOL? Not sure how much community has formed around it (I mean, I’ve never encountered RED in the wild…), but it always struck me as interesting, at least.
Red is super neat. Last I looked (which was a long time ago) at it they didn’t support a View-like dialect on anything but Windows but it looks like that’s changed! That’s awesome. Good for them. I’ll need to look at it again.
The interval example is just one example, I also want to be able to do something like
type SortedList[T] <: List[T] {
T is Comparable
forall x, y in 0..Len(self):
x < y => self[x] < self[y]
}
def binary_search(l: SortedList[T], elem: T) {
...
}
Possible in Ada 2012, without using SPARK. You can also use Preconditions/Postconditions in Ada 2012 without requiring proofs, as a runtime assertion mechanism.
-- Rough, probably doesn't compile as is, but this is the idea:
generic
type T (<>) is private;
package Lists
type List(Length : Natural) is record
Elements : array(Natural range <>) of T;
end record
with Type_Invariant => Is_Sorted;
function Is_Sorted(L : List) return Boolean;
end Lists;
sort-list: broke its own contract
promised: (sorted-listof integer?)
produced: '(1 3 2)
in: an and/c case of
the range of
(->
(listof integer?)
(and/c
(listof integer?)
(sorted-listof integer?)))
contract from: (function sort-list)
blaming: (function sort-list)
(assuming the contract is correct)
at: /Users/bogdan/tmp/sorted-list.rkt:24:18
Context (errortrace):
/Users/bogdan/tmp/sorted-list.rkt:28:0: (sort-list (quote (1 2 3)))
Note how the same contract now blames the sort-list function, not the caller.
No, I’m not. Dependent types are push you into the formal methods space. I specifically want to try using these kinds of things without having to also play Fight The Theorem Prover. I do enough of that for work!
To my knowledge, dependent types are very static. Here is the context for the interval example in Hillel’s article:
Static types are great! There’s lots of cool stuff being done with static typed languages right now. Not so much with dynamic types, though. Most of the research and interest is in adding gradual typing to dynamic languages. I think there’s a lot of interesting experiments we can do with dynamic types. I mean, you can generate new types at runtime! Combine that with contracts and we can attach constraints to variables, like this:
I don’t think that’s a very useful distinction. While the types are technically static, the actual types of objects may not be resolved until runtime (potentially resulting in type errors). This is pretty dynamic behavior for a “static” type system.
If you’re already willing to accept dynamic types, and contracts, doesn’t mixing the two get you all the way there? You need contracts on the class / structure, not just pre/post conditions on functions and methods. But this is already established, in say, Eiffel. Are you merely asking for more expressive invariants?
A more interesting idea would be adding and removing types to values as they move around. Like calling sort on a list returns a SortedList, and then shuffling the SortedList returns a regular list. I dunno. I’m spitballing here, I think there’s interesting ideas you could do with dynamic types that haven’t been done yet, but maybe I need to think more about those actually are.
Something else I’ve wanted to play with are “contagious types”: 2 * ViralNum(2) == ViralNum(4). Don’t think this would be useful for anything, but I just want to play with it.
EDIT: actually I think the thing I really want is to be able to say “TestableObj is a subtype of Obj, now replace *every instance of Obj with TestableObj in this program run, kthx”. I think it’s a similar idea to the “semantic relations”. I’d really like to see the contracts/semantic relations/wild metaprogramming all in one language.
“contagious types”: 2 * ViralNum(2) == ViralNum(4). Don’t think this would be useful for anything
One application would be to have a number type where you mark numbers as “inexact” if they come from special inexact numerals, or if they are the result of a floating point operation where the overflow / underflow / inexact flags were set, or if an argument to the operation is inexact. Scheme uses this same terminology for a feature that is less useful than what I just described.
This is related to tainted values in Perl, which are useful for enforcing security policies. Say you want to fix Javascript to prevent fingerprinting. Any Javascript operation that returns a value that can be used for fingerprinting is tainted. If a tainted value is used to construct another value, the second value is also tainted. Then you have a security restriction that prevents tainted values from being transmitted to another host over a network connection (or added to a cookie, same thing).
EDIT: actually I think the thing I really want is to be able to say “TestableObj is a subtype of Obj, now replace *every instance of Obj with TestableObj in this program run, kthx”. I think it’s a similar idea to the “semantic relations”. I’d really like to see the contracts/semantic relations/wild metaprogramming all in one language.
Can’t this be achieved today with something like Guice, or other Dependency Injection frameworks?
It looks like that requires you to modify the original class to get the desired behavior? I was thinking of applying it to, say, objects coming from a third party library.
These frameworks are kind of viral, but you can create “modules” — a rule set, basically — and swap per execution. Something, somewhere is going to need to make a choice about which type / constructor to use instead, so it’s unlikely that you’ll get away without modifying something. In the case you mention, you’d likely have to use a proxy, so, you’re still modifying something.
Heh, the only thing I think I need is some variant of ML with rust-level quality of implementation. Specifically, I think I need:
Functional programming language (as in “programming with values”, not as in “programming with category theory”)
Aimed at high-level programs (think Java/Go/Swift/Python/Ruby/C#)
With ruthless focus on human side in the human-computer continuum (so, all ints are big ints, no thinking about stack vs heap, no async in surface-syntax)
And reasonable concurrency story (either Erlant-style separte heaps, or, if someone invents Send/Sync+borrow checker which is not hard, that)
With low-overhead implementatin (seamlessly works on all platforms, fast to compile, static binaries)
And a minimal type-system which strongly encourages low-abstraction code, but still allows implementing JSON serialization in a non-horrible way.
Basically, today I use Rust for everything because it “just works” more than anything else I’ve tried (didn’t’ try Go though), but I really don’t need blazing fastness for eg, my shell scripts. OCaml is in theory what I need, but I find it’s quality of implementation lacking.
Reading the list, I was definitely thinking that OCaml almost fits the bill. Its compiler is actually very good (when it comes to emitting correct code, being fast, and having few compiler bugs).
What is lacking is indeed a few “modern” things:
no standard deriving/serde (where rust clearly shines)
bigints are not the default (zarith is neat but it’s not as seamless as int)
the portability/static binary story is lacking.
It’s really sad, because OCaml with some of Go’s tooling qualities would be incredible. Maybe someone will step up and develop the next ML :-).
Yeah, OCaml is frustratingly close, but I also have a few gripes with its inner workings:
objects are redundant
polymorphic equality/hash/comparison is awkward, which is a sign of a deeper ad-hoc polymorphism issue
compilation model with a shared global namespace and without explicit DAG of dependencies is pretty horrible (ocamldep is one of the grossest hacks in my book)
ocaml objects aren’t any more redundant than any feature in any language that has more than one way to do things. they may not be much used due to cultural/ecosystem choices, but every now and then they are the most ergonomic solution to what i’m trying to do.
the namespace issues are indeed a pain though :( after getting a day job working in python i have been dissatisfied with namespacing in both ruby and ocaml, which are otherwise two of my favourite languages.
Rust prioritizes machine friendliness over human friendliness, the entire language is basically build around stack/heap distinction
OCaml suffers from QoI issues (elaborated in a different comment)
Haskell suffers from different QoI issues (fragmentation due to language pragmas, opaque behavior due to laziness, forces the programmer on the path of programming with categories rather than programming with values, build/packaging issues)
Swift kinda at least is in the right ballpark I think, but there’s a big issue of platform comparability: if I understand correctly, a lot of weight is pulled by MacOS specific foundation library. And it also has quite a bit more complex type system than I think is optimal.
Kotlin is kinda like Swift: great direction, but suffers from JVM platform and from comparability with Java.
When people talk about functional programming, two different pictures come to mind.
One is that of an advanced type-system, with roots in category theory. Keyword here is “monad”. This style of programming focuses on producing highly abstract, high order code, where you not so much do things directly, but rather provide an abstract description of computation in a DSL. Prime examples of this aspect of FP are Haskell and certain corners of Scala ecosystem.
The different picture is that of non-imperative programming. Basically, everything is an immutable data structure, so every bit of program logic is just a function which takes some value as an input, and produces a different value as an output. Keyword would be “Algebraic Data Type”. This style of programming is direct: the code describes a sequence of transformation steps, it is mostly first-order. Prime examples of this aspect of FP are Clojure and Erlang, to a lesser extent OCaml, and, among more obscure languages, Elm.
In my personal style I of programming, I’ve found that I really enjoy directness and simplicity, and that I fight overuse of abstraction more often than the lack of it. I am basically a Go programmer in my heart. So, I run towards FP as programming with values, and look skeptically at FP as programming with categories.
Doesn’t Erlang/Elixir almost fill the bill. The only place where it lacks a little is 5th point, but:
With releases where you do not use NIFs you can just compile once, run everywhere (as soon as you have runtime)
You can build cross-releases with the ERTS included into the release which make the deployment almost self-contained (and with statically linked source ERTS is is self contained)
There are project like Burrito that make all the above much simpler.
Yeah, I think Erlang’s runtime is quite close to what I want. I do need mandatory static types though, as they unlock a lot of automated tooling with strong guarantees of correctness.
D is kind of that, but somewhat more heavily weighted towards allowing performance optimization. So generally you don’t need to think about stack/heap etc, but you can if you want to. And you need to put in a bit of effort to use it in a pure functional style, but it’s very possible.
OCaml comes close… so does F# except for the static binaries. Scala native could be considered too… the runtime seems light but the concurrency story is missing. SML+pony runtime tacked on would be lovely.
Yes, I do want quite a bunch of things, but I want only the boring things: I don’t need dependent types, give me rather a build system which doesn’t make me cry :)
SML+pony runtime tacked on would be lovely.
Yeah, someone here said once “Go should have been SML with channels”, and yes, that’s a good terse approximation to what I want.
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
Unholy but I’m into it.
A language designed around having first-class GUI support. I miss VB6.
That sixth language feature shows up in several lineages of Smalltalk. I’m most familiar with the lineage that contains E and my spinoff language Monte, but I think it also shows up in Newspeak and Objective-Smalltalk. We generally call them “guard objects” or just “guards” in E, by analogy with guard clauses. The E lineage has syntactic sugar for interval guards. In E-on-Java:
? var i :(1..10) := 3
# value: 3
? i += 7
# value: 10
? i += 1
# problem: 11 is not in the region 1..!11
In Monte using the Typhon VM:
⛰ var i :(1..10) := 3
Result: 3
⛰ i += 7
Result: 10
⛰ i += 1
Exception: 11 is not in <[1, 10] Int region>
Edit: Here is the sorted-list example from another thread. E/Monte guards are Turing-complete.
⛰ def SortedList.coerce(l :List, ej) { for i in (0..!l.size() - 1) { def j := i + 1; if (l[i] > l[j]) { throw.eject(ej, `list not sorted at ($i..$j)`) } }; return l }
Result: <SortedList>
⛰ def l1 :SortedList := [1,2,3]
Result: [1, 2, 3]
⛰ def l2 :SortedList := [3,2,1]
Exception: list not sorted at (0..1)
In prototype-based languages you can give any object its own methods, so singleton types are trivial. Besides Self and JS, this shows up in the (many) languages designed for creating text adventures / interactive fiction / MUDs — two good examples are Inform and MOO. In such a game it’s obvious that you’d want to make lots of one-off objects with unique behavior, like the paper sack in Zork.
The problem with this is the only thing you’re saving is one line of globals.room123 = new Room123(), yet you give up the ability to screw around with disposable instances for the purposes of testing.
Graphs are really common data structures but there hasn’t yet been an “everything’s a graph” language
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 is 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:
The standard bearer for contracts used to be Eiffel, which people stopped caring about in the mid-90’s.
*sniffs* I care! I still care! I actually have a signed copy of Object-Oriented Software Construction II in a box of books somewhere.
More seriously, I’m basically done with OO inheritance, and am glad to use interfaces / traits instead. There’s probably more that can be done in the direction of Design by Contract for this, beyond unit tests.
Everything is a Graph
Actually, I would like someone to create a Lisp based around a Lua table. Something that goes further than Lua itself does. Where all the code has a canonical representation as a table as well, to make macro writing easier. Also the metatable stuff in Lua is a little clunky, so perhaps more integrated support for that would also be great.
I just have a feeling that there’s a really powerful and compact design (and implementation) for a language based around this idea. Maybe not as small and concise as Forth, but still pretty small.
Eh, I don’t know. I spend my fun-time writing Rust these days, which is neither dynamic nor has a small and compact design or implementation.
You may find what you’re looking for in the various “cola”-pun-named implementations by VPRI and friends. I’m having a hard time finding links right now tho :(
Pretty much all of these exist today. That doesn’t mean they’re good ideas.
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.
Emacs. This is the worst aspect of Elisp.
A language with semantic relations
That’s the goal of Haskell and in most cases it works extremely well. If the type is exact enough and the function is pure, you read the type, you know what it does. Replacing one function with another is fine as long as the types match. Of course, this depends on well your types model your problem.
Everything is a Graph
We live in the wrong universe for this. Had RAM continued to be very fast relative to CPUs this would make sense. In our universe, it’s like shooting yourself in the foot.
A serious take on a contract-based language … Clojure
Racket has far better contract support than Clojure. Arguably, Racket’s contracts are even better than Eiffel’s.
A really dynamically-typed language … I want to write metaprograms dammit
Nice. Everything in this list is something I want in the next language I design, except for the graphs. I actually prefer that everything is a tree. My current language (Curv) is a research prototype that approaches this stuff, but it’s not all the way there.
Instead of being inspired by J, I’m inspired by K. K has numbers, characters, symbols, lists, records and functions (anonymous function literals that make closures). Multidimensional arrays are represented by nested lists. There is need for “boxes”. J has more built in operations, but K has a richer and I think more elegant set of datatypes. I’m particularly bothered by the fact that J doesn’t have lambda expressions or closures: that’s why I never learned it.
Live programming and reactive programming is something I want. I think there’s a lot of room for innovation here, designing new UIs that are clear, intuitive and powerful (and not “absolutely hell to learn”). Mathematica notebooks are a good starting point. Actually, Mathematica is a good starting point for several of the requests in this post. I leaned on Mathematica a bit when designing parts of my current language. Like K, it also represents multi-dimensional arrays as nested lists.
As far as I know, the only way to create a closure in k is to partially apply a function. No? You can do exactly the same thing in j, using & (bond).
As for ‘lambda expressions’, it was always possible to write them, using syntax like 4 :'x+y'. More convenient syntax was added recently, cf {{x+y}}.
But this was traditionally minimised due to the role of tacit programming, which provides an alternate, and, to my eye, much more elegant method of writing functions and programs ‘in-line’.
Tacit programs are also inherently closed, minimising the need for ‘closures’.
There are so many versions and implementations of K that maybe they don’t all support closures or maybe there are bugs. In Kona I can do this:
> f:{[a]{[b]a+b}}
> g:f 2
> g 3
5
K functions can have any number of arguments (not restricted to 1 or 2), you can partially apply them, you can create closures using lexical scoping. There are function literals. I couldn’t find these features in J when I looked a few years ago, thanks for telling me about the 4 : operator.
For calculator thingy there is Calca that I use. Maybe it do not fit the description 100%, but it is pretty close. Each free variable in the assignment creates function that can be later bound when calling.
For example Birthday Paradox solver can be written as
## Birthday paradox
It will give aproximate value
n - amount of the people
d - number of distinguish days
p = 1 - e^(-n * (n - 1) / 2d) => -e^(-0.5 n^2/d + 0.5 n/d) + 1
a = n(p = .25, d = 2**32) => [49,711.3659, -49,710.3659]
Nice thing is that it is still Markdown document (with extensions obviously), so we can have more context there as well.
People are always so so confused about what asserts mean, and hence we miss so many opportunities for safety AND performance.
Wouldn’t it be nice if a compiler could warn us it there was any path on which a precondition check could fail?
Wouldn’t it be nice if the precondition checks informed the optimizer about characteristics and relationships of the variables involved?
Awhile back I said on this forum it would be interesting to have a doubly link list based language… and it took me quite some time to spot the obvious flaw. You can’t have (cheap) immutable data structures .
But yes, a digraph as a first class citizen would be very useful. It really is a pretty fundamental data structure.
I have lost my fear of metaprogramming. They’re just another program. And like any other program they the intermediate results need to be readable, inspectable, debugable and testable.
And yes, graphics on a ye olde 6502 based UK101 was much easier than anything today.
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
Maybe I misunderstand, but in the general case wouldn’t it be impossible to have the compiler tell you if two functions were identical, unless the input space was finite (halting problem)?
J / desktop calculator with good other stuff like JSON, etc.
I feel like there might be a project around that allows embedding J into python or something like that. If not J, BQN or APL… But yeah, I feel this one. I just do some stuff in J and other stuff elsewhere. Wolfram is another good contender here. It’s got a reasonably terse language, and an infinity of builtins for every task you can ever want. Not a trivial learning curve, though.
Maybe I misunderstand, but in the general case wouldn’t it be impossible to have the compiler tell you if two functions were identical, unless the input space was finite (halting problem)?
There’s a few things we could do here:
Create a runtime contract that every time window2 is called, compare the output to window1 and see if they match
Generate a property test
Randomly swap window2 for window1 in other tests to see if they get the same results
Probably other stuff, I’m just one guy
Not a trivial learning curve, though.
I mean, I know TLA+ and J, horrible learning curves don’t really bother me :P
I mean, I know TLA+ and J, horrible learning curves don’t really bother me :P
:)
Especially if you are interested in math, which I know you are, Wolfram is a pretty amazing language to know. I am not an expert, but even with the medium amount I know it provides incredible power. It is just so high-level. You can compute anything, easily create visualizations (eg, if you scroll down to “Solutions to last week’s riddler”, I created the monte carlo visualization there in under 10m), even one off UIs, all in few lines of code in a notebook.
I want to write about this at some point, but I also find it fascinating that in some sense, from a “language organization” perspective, it takes the opposite approach of the APL-likes. In the APLs, you painstakingly design ~50 primitives, which all work together collaboratively, and with just those you can solve more or less every problem. But the “work”, so to speak, is pushed onto the user, who must be familiar with many idioms and with how to combine the primitives to solve their problem.
In Wolfram, the approach is “a builtin for everything”. There are literally thousands. And then they solve the problem of discoverability by having really good docs that can be searched inline as you are coding. So the language and IDE/environment/docs are really two sides of a single coin.
I think Ioke was originally created as a vehicle to explore extreme dynamism. Its author (Ola Bini) worked with Ruby and Io (an awesome language in itself) and wondered how much more dynamic things could be. IIRC while working on Ioke, Ola realised Ioke needed some simplifications and improvements (chiefly immutability) and then created a follow-up language Seph - read more on it in the pre-announcement.
AFAIK they’re both kinda dead now, unfortunately. Not sure why - maybe the author ran out of steam. There wasn’t much of an uptake by the wider community IIRC.
From TFA:
You can do this in Ada, and it will even detect it at compile-time in most cases:
Gives me
Also from TFA:
I miss REBOL. :(
Isn’t Red the logical successor of REBOL? Not sure how much community has formed around it (I mean, I’ve never encountered RED in the wild…), but it always struck me as interesting, at least.
Red is super neat. Last I looked (which was a long time ago) at it they didn’t support a View-like dialect on anything but Windows but it looks like that’s changed! That’s awesome. Good for them. I’ll need to look at it again.
The interval example is just one example, I also want to be able to do something like
Possible in Ada 2012, without using SPARK. You can also use Preconditions/Postconditions in Ada 2012 without requiring proofs, as a runtime assertion mechanism.
Actual Example of Type_Invariant Usage, which has Pre/Post usage in the same file
[Comment removed by author]
[Comment removed by moderator pushcx: Let's not do 4chan.]
Racket makes this sort of stuff trivial:
Produces:
And blame works in the opposite way, too:
Produces:
Note how the same contract now blames the
sort-list
function, not the caller.You’re looking for something with dependent types. ex: https://mazzo.li/posts/AgdaSort.html https://github.com/davidfstr/idris-insertion-sort/blob/master/InsertionSort.idr
No, I’m not. Dependent types are push you into the formal methods space. I specifically want to try using these kinds of things without having to also play Fight The Theorem Prover. I do enough of that for work!
Well, that’s the name for this sort of thing.
To my knowledge, dependent types are very static. Here is the context for the interval example in Hillel’s article:
I don’t think that’s a very useful distinction. While the types are technically static, the actual types of objects may not be resolved until runtime (potentially resulting in type errors). This is pretty dynamic behavior for a “static” type system.
I think you could get close to something like that with Ada/SPARK. I’m no expert though.
EDIT: See @pyj ’s much better response above.
If you’re already willing to accept dynamic types, and contracts, doesn’t mixing the two get you all the way there? You need contracts on the class / structure, not just pre/post conditions on functions and methods. But this is already established, in say, Eiffel. Are you merely asking for more expressive invariants?
A more interesting idea would be adding and removing types to values as they move around. Like calling
sort
on a list returns aSortedList
, and then shuffling the SortedList returns a regular list. I dunno. I’m spitballing here, I think there’s interesting ideas you could do with dynamic types that haven’t been done yet, but maybe I need to think more about those actually are.Something else I’ve wanted to play with are “contagious types”:
2 * ViralNum(2) == ViralNum(4)
. Don’t think this would be useful for anything, but I just want to play with it.EDIT: actually I think the thing I really want is to be able to say “
TestableObj
is a subtype ofObj
, now replace *every instance ofObj
withTestableObj
in this program run, kthx”. I think it’s a similar idea to the “semantic relations”. I’d really like to see the contracts/semantic relations/wild metaprogramming all in one language.One application would be to have a number type where you mark numbers as “inexact” if they come from special inexact numerals, or if they are the result of a floating point operation where the overflow / underflow / inexact flags were set, or if an argument to the operation is inexact. Scheme uses this same terminology for a feature that is less useful than what I just described.
This is related to tainted values in Perl, which are useful for enforcing security policies. Say you want to fix Javascript to prevent fingerprinting. Any Javascript operation that returns a value that can be used for fingerprinting is tainted. If a tainted value is used to construct another value, the second value is also tainted. Then you have a security restriction that prevents tainted values from being transmitted to another host over a network connection (or added to a cookie, same thing).
Can’t this be achieved today with something like Guice, or other Dependency Injection frameworks?
It looks like that requires you to modify the original class to get the desired behavior? I was thinking of applying it to, say, objects coming from a third party library.
These frameworks are kind of viral, but you can create “modules” — a rule set, basically — and swap per execution. Something, somewhere is going to need to make a choice about which type / constructor to use instead, so it’s unlikely that you’ll get away without modifying something. In the case you mention, you’d likely have to use a proxy, so, you’re still modifying something.
Re: contagious types, they can be useful for expressing measurement units. Here’s an example in Julia using the Unitful package:
Some Julia packages also use “contagious types” for tracking the error on a calculation, derivatives, etc.
[Comment removed by author]
Heh, the only thing I think I need is some variant of ML with rust-level quality of implementation. Specifically, I think I need:
Basically, today I use Rust for everything because it “just works” more than anything else I’ve tried (didn’t’ try Go though), but I really don’t need blazing fastness for eg, my shell scripts. OCaml is in theory what I need, but I find it’s quality of implementation lacking.
Reading the list, I was definitely thinking that OCaml almost fits the bill. Its compiler is actually very good (when it comes to emitting correct code, being fast, and having few compiler bugs).
What is lacking is indeed a few “modern” things:
int
)It’s really sad, because OCaml with some of Go’s tooling qualities would be incredible. Maybe someone will step up and develop the next ML :-).
Yeah, OCaml is frustratingly close, but I also have a few gripes with its inner workings:
ocaml objects aren’t any more redundant than any feature in any language that has more than one way to do things. they may not be much used due to cultural/ecosystem choices, but every now and then they are the most ergonomic solution to what i’m trying to do.
the namespace issues are indeed a pain though :( after getting a day job working in python i have been dissatisfied with namespacing in both ruby and ocaml, which are otherwise two of my favourite languages.
Seems like any of Haskell/OCaml/Rust/Swift fits this bill depending on your other tastes.
Not at all:
Swift kinda at least is in the right ballpark I think, but there’s a big issue of platform comparability: if I understand correctly, a lot of weight is pulled by MacOS specific foundation library. And it also has quite a bit more complex type system than I think is optimal.
Kotlin is kinda like Swift: great direction, but suffers from JVM platform and from comparability with Java.
Would you mind elaborating on this distinction? It’s the first time I’ve heard it made.
When people talk about functional programming, two different pictures come to mind.
One is that of an advanced type-system, with roots in category theory. Keyword here is “monad”. This style of programming focuses on producing highly abstract, high order code, where you not so much do things directly, but rather provide an abstract description of computation in a DSL. Prime examples of this aspect of FP are Haskell and certain corners of Scala ecosystem.
The different picture is that of non-imperative programming. Basically, everything is an immutable data structure, so every bit of program logic is just a function which takes some value as an input, and produces a different value as an output. Keyword would be “Algebraic Data Type”. This style of programming is direct: the code describes a sequence of transformation steps, it is mostly first-order. Prime examples of this aspect of FP are Clojure and Erlang, to a lesser extent OCaml, and, among more obscure languages, Elm.
In my personal style I of programming, I’ve found that I really enjoy directness and simplicity, and that I fight overuse of abstraction more often than the lack of it. I am basically a Go programmer in my heart. So, I run towards FP as programming with values, and look skeptically at FP as programming with categories.
Doesn’t Erlang/Elixir almost fill the bill. The only place where it lacks a little is 5th point, but:
Yeah, I think Erlang’s runtime is quite close to what I want. I do need mandatory static types though, as they unlock a lot of automated tooling with strong guarantees of correctness.
There is Gleam by @lpil that may fit your needs.
D is kind of that, but somewhat more heavily weighted towards allowing performance optimization. So generally you don’t need to think about stack/heap etc, but you can if you want to. And you need to put in a bit of effort to use it in a pure functional style, but it’s very possible.
“only thing”? you seem to want everything :)
OCaml comes close… so does F# except for the static binaries. Scala native could be considered too… the runtime seems light but the concurrency story is missing. SML+pony runtime tacked on would be lovely.
Yes, I do want quite a bunch of things, but I want only the boring things: I don’t need dependent types, give me rather a build system which doesn’t make me cry :)
Yeah, someone here said once “Go should have been SML with channels”, and yes, that’s a good terse approximation to what I want.
“SML with channels” sounds like Erlang to me….
Unholy but I’m into it.
Yeah.
Swizzling! https://nshipster.com/method-swizzling/
Seems like all the sensible use cases for such run-time magic would all be better-suited to a more flexible dev-time and build-time toolkit though.
That sixth language feature shows up in several lineages of Smalltalk. I’m most familiar with the lineage that contains E and my spinoff language Monte, but I think it also shows up in Newspeak and Objective-Smalltalk. We generally call them “guard objects” or just “guards” in E, by analogy with guard clauses. The E lineage has syntactic sugar for interval guards. In E-on-Java:
In Monte using the Typhon VM:
Edit: Here is the sorted-list example from another thread. E/Monte guards are Turing-complete.
In prototype-based languages you can give any object its own methods, so singleton types are trivial. Besides Self and JS, this shows up in the (many) languages designed for creating text adventures / interactive fiction / MUDs — two good examples are Inform and MOO. In such a game it’s obvious that you’d want to make lots of one-off objects with unique behavior, like the paper sack in Zork.
Kotlin also has the
object
syntax for creating singletons.The problem with this is the only thing you’re saving is one line of
globals.room123 = new Room123()
, yet you give up the ability to screw around with disposable instances for the purposes of testing.Not a full programming language, but RDF query languages (OWL etc.) seem to fit the bill. (Not GraphQL though, despite the name.)
Actually maybe the Cell language that was linked to here a few weeks ago? I’ve still got a tab open on it; it’s fascinating.
Graphs are really common data structures but there hasn’t yet been an “everything’s a graph” language
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
The whole heap is graph-shaped!
It is 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
*sniffs* I care! I still care! I actually have a signed copy of Object-Oriented Software Construction II in a box of books somewhere.
More seriously, I’m basically done with OO inheritance, and am glad to use interfaces / traits instead. There’s probably more that can be done in the direction of Design by Contract for this, beyond unit tests.
Actually, I would like someone to create a Lisp based around a Lua table. Something that goes further than Lua itself does. Where all the code has a canonical representation as a table as well, to make macro writing easier. Also the metatable stuff in Lua is a little clunky, so perhaps more integrated support for that would also be great.
I just have a feeling that there’s a really powerful and compact design (and implementation) for a language based around this idea. Maybe not as small and concise as Forth, but still pretty small.
Eh, I don’t know. I spend my fun-time writing Rust these days, which is neither dynamic nor has a small and compact design or implementation.
You may find what you’re looking for in the various “cola”-pun-named implementations by VPRI and friends. I’m having a hard time finding links right now tho :(
I did look briefly at vpri.org and harc.ycr.org, but both sites have issues with their SSL certs. I’ll have to check them out in more detail later.
Pretty much all of these exist today. That doesn’t mean they’re good ideas.
Emacs. This is the worst aspect of Elisp.
That’s the goal of Haskell and in most cases it works extremely well. If the type is exact enough and the function is pure, you read the type, you know what it does. Replacing one function with another is fine as long as the types match. Of course, this depends on well your types model your problem.
We live in the wrong universe for this. Had RAM continued to be very fast relative to CPUs this would make sense. In our universe, it’s like shooting yourself in the foot.
Racket has far better contract support than Clojure. Arguably, Racket’s contracts are even better than Eiffel’s.
Racket again, it’s all about metaprogramming.
I was going to tag Hillel with this article on twitter, “this seems right up your alley!” and then I read the URL correctly. 🤦
Nice. Everything in this list is something I want in the next language I design, except for the graphs. I actually prefer that everything is a tree. My current language (Curv) is a research prototype that approaches this stuff, but it’s not all the way there.
Instead of being inspired by J, I’m inspired by K. K has numbers, characters, symbols, lists, records and functions (anonymous function literals that make closures). Multidimensional arrays are represented by nested lists. There is need for “boxes”. J has more built in operations, but K has a richer and I think more elegant set of datatypes. I’m particularly bothered by the fact that J doesn’t have lambda expressions or closures: that’s why I never learned it.
Live programming and reactive programming is something I want. I think there’s a lot of room for innovation here, designing new UIs that are clear, intuitive and powerful (and not “absolutely hell to learn”). Mathematica notebooks are a good starting point. Actually, Mathematica is a good starting point for several of the requests in this post. I leaned on Mathematica a bit when designing parts of my current language. Like K, it also represents multi-dimensional arrays as nested lists.
As far as I know, the only way to create a closure in k is to partially apply a function. No? You can do exactly the same thing in j, using & (bond).
As for ‘lambda expressions’, it was always possible to write them, using syntax like 4 :'x+y'. More convenient syntax was added recently, cf {{x+y}}.
But this was traditionally minimised due to the role of tacit programming, which provides an alternate, and, to my eye, much more elegant method of writing functions and programs ‘in-line’.
Tacit programs are also inherently closed, minimising the need for ‘closures’.
There are so many versions and implementations of K that maybe they don’t all support closures or maybe there are bugs. In Kona I can do this:
K functions can have any number of arguments (not restricted to 1 or 2), you can partially apply them, you can create closures using lexical scoping. There are function literals. I couldn’t find these features in J when I looked a few years ago, thanks for telling me about the
4 :
operator.For calculator thingy there is Calca that I use. Maybe it do not fit the description 100%, but it is pretty close. Each free variable in the assignment creates function that can be later bound when calling.
For example Birthday Paradox solver can be written as
Nice thing is that it is still Markdown document (with extensions obviously), so we can have more context there as well.
If you’re into Object Pascal, Lazarus is all about UI programming like old VB6. Your just have to be into Object Pascal…
People are always so so confused about what asserts mean, and hence we miss so many opportunities for safety AND performance.
Wouldn’t it be nice if a compiler could warn us it there was any path on which a precondition check could fail?
Wouldn’t it be nice if the precondition checks informed the optimizer about characteristics and relationships of the variables involved?
Awhile back I said on this forum it would be interesting to have a doubly link list based language… and it took me quite some time to spot the obvious flaw. You can’t have (cheap) immutable data structures .
But yes, a digraph as a first class citizen would be very useful. It really is a pretty fundamental data structure.
I have lost my fear of metaprogramming. They’re just another program. And like any other program they the intermediate results need to be readable, inspectable, debugable and testable.
And yes, graphics on a ye olde 6502 based UK101 was much easier than anything today.
Dart + Flutter?
Maybe I misunderstand, but in the general case wouldn’t it be impossible to have the compiler tell you if two functions were identical, unless the input space was finite (halting problem)?
I feel like there might be a project around that allows embedding J into python or something like that. If not J, BQN or APL… But yeah, I feel this one. I just do some stuff in J and other stuff elsewhere. Wolfram is another good contender here. It’s got a reasonably terse language, and an infinity of builtins for every task you can ever want. Not a trivial learning curve, though.
There’s a few things we could do here:
window2
is called, compare the output towindow1
and see if they matchwindow2
forwindow1
in other tests to see if they get the same resultsI mean, I know TLA+ and J, horrible learning curves don’t really bother me :P
:)
Especially if you are interested in math, which I know you are, Wolfram is a pretty amazing language to know. I am not an expert, but even with the medium amount I know it provides incredible power. It is just so high-level. You can compute anything, easily create visualizations (eg, if you scroll down to “Solutions to last week’s riddler”, I created the monte carlo visualization there in under 10m), even one off UIs, all in few lines of code in a notebook.
I want to write about this at some point, but I also find it fascinating that in some sense, from a “language organization” perspective, it takes the opposite approach of the APL-likes. In the APLs, you painstakingly design ~50 primitives, which all work together collaboratively, and with just those you can solve more or less every problem. But the “work”, so to speak, is pushed onto the user, who must be familiar with many idioms and with how to combine the primitives to solve their problem.
In Wolfram, the approach is “a builtin for everything”. There are literally thousands. And then they solve the problem of discoverability by having really good docs that can be searched inline as you are coding. So the language and IDE/environment/docs are really two sides of a single coin.
I think Ioke was originally created as a vehicle to explore extreme dynamism. Its author (Ola Bini) worked with Ruby and Io (an awesome language in itself) and wondered how much more dynamic things could be. IIRC while working on Ioke, Ola realised Ioke needed some simplifications and improvements (chiefly immutability) and then created a follow-up language Seph - read more on it in the pre-announcement.
AFAIK they’re both kinda dead now, unfortunately. Not sure why - maybe the author ran out of steam. There wasn’t much of an uptake by the wider community IIRC.
Pluto.jl might float your boat. It does reactive notebooks with Julia.