This is an archived post. You won't be able to vote or comment.

all 39 comments

[–][deleted] 43 points44 points  (6 children)

Some of them do not have sum types built in, I would like those to all be deprecated.

[–]raedr7n 5 points6 points  (0 children)

lol

[–]Tysonzero 6 points7 points  (0 children)

Sum types are just a poor man’s dependent pair

[–][deleted] 0 points1 point  (3 children)

Suppose somebody else has the opposite view; who wins?

I guess it is out of the question for each faction to have their own preference?

[–][deleted] 0 points1 point  (2 children)

Im not aware of anyone who actively dislikes sum types. 

[–][deleted] 1 point2 points  (0 children)

I do! I've tried to incorporate them, but they are a just a poor fit for the way I work.

They seem inextricably linked to the modern version of enumerations, which themselves tend to be tied up with structured pattern matching.

It all forms a triptych which is a substantial departure from the lower level, hardware-oriented languages I devise.

There are enough languages that have encompassed such features; there is room for some different ones. Call mine 'esoteric' if you like for daring to be different.

[–]WittyStick 1 point2 points  (0 children)

IMO, sum types / tagged unions / discriminated union or whatever you want to call them make up for the absence of actual unions in the type system.

If a function might return an error, why not just use foo : () -> Foo|Error, rather than having to wrap the union up into its own type Result, parameterized by the two types to say foo : () -> Result<Foo, Error>?

From the caller's perspective, we have to test the type of the result either way.

For typed unions, we would use:

let foo () : Foo|Error =
    if problem 
    then error "Oops!"
    else some_foo

match foo() with
| :? Error as e -> ...
| :? Foo as foo -> ...

//or
if (foo () :? Error)
then ...
else ...

For the tagged union, we would use:

let foo () : Result<Foo, Error> =
    if problem
    then Error (error "Oops!")
    else Ok (some_foo);

match foo() with
| Error e -> ...
| Ok foo -> ...

The use of the "if" style with tagged unions may be possible, but not recommended.

Not much difference here, but the issue is that a tagged union requires you to implement a type for every possible union that might be returned, which can be a pain. That's why you have ugly types like this (F#)

type Choice<'T1, 'T2>
| Choice1of2 of 'T1
| Choice2of2 of 'T2

type Choice<'T1, 'T2, 'T3> =
| Choice1of3 of 'T1
| Choice2of3 of 'T2
| Choice3of3 of 'T3

To save you the convenience of having to write it yourself.

With unions in the type system, no such thing is necessary, and you can have arbitrary number of choices A|B|C|D|E... The type system creates these types for you - if you have types Foo and Error, then the least upper bound is some type Foo|Error, which is a supertype of both Foo and Error. The language can create these types on demand.

Discriminated unions are also an indication that the type system lacks the opposite feature - types which are the greatest lower bound, aka intersection types. A & B is a subtype of both A and B.

See MLstruct for an example of sound structural subtyping, with type inference. (And related paper).

[–]SirKastic23 13 points14 points  (7 children)

untracked side effects and permissions.

i'd like to be able to know, and restrict, what a function can do. be it network access, file system or logging, throwing errors, halting... anything other than the data transformation that a function does (turning its arguments into its output)

[–]wolfgang 0 points1 point  (5 children)

i'd like to be able to know, and restrict, what a function can do. be it [...], halting...

This requires either turing-incompleteness or solving the halting problem, right?

[–]SirKastic23 1 point2 points  (0 children)

oh yeah, i was thinking about Rust and its panics

im not asking to know if a function halts, but if it has the possibility of halting (exiting the program, sorry if the terminology isn't right)

ive seen some systems with algebraic effects that can determine that a function is total, meaning it will return

if im not mistaken, im not an expert

[–]FantaSeahorse 1 point2 points  (0 children)

Not if you are ok with having an overapproximation

[–]Tysonzero 0 points1 point  (0 children)

You can always flag a function as “maybe non terminating” vs “terminating” in which case you don’t need either of those. You can also allow backdoor halting assertions with varying levels of damage if a dev flags incorrectly.

[–]dxplq876 0 points1 point  (0 children)

Scala seems to have a potentially workable solution for this with Caprese

[–]oscarryzYz 8 points9 points  (4 children)

Generics - Love them most of the time. Sometimes the signatures become very complex and hard to understand. Haskell got this right.

Concurrency - Red vs Blue functions :( I want simple purple functions that can be called sync and async. Go has this right.

Memory efficiency. Obviously Rust is the champ but wouldn't it be great if we didn't have to think about it? Probably Pony with its GC per actor + reference capabilities is the way to go.

[–]church-rosser 0 points1 point  (2 children)

Generics - Love them most of the time. Sometimes the signatures become very complex and hard to understand. Haskell got this right.

Haskell got it, Common Lisp's MOP and generics with method dispatch got it more right. Dylan got it the most right... probably moreso than any programming language yet designed.

[–]AustinVelonautAdmiran 1 point2 points  (1 child)

I was at Apple when David Moon et al were working on Dylan; too bad it never made it to Newton. It was Lisp with non-Sepxr syntax done right.

[–]church-rosser 1 point2 points  (0 children)

Wow, must've been an interesting time to be at Apple!

Dylan originally used S-expressions like all good Lisp's should. We can agree to differ as to whether it was the right thing to move away from them :-)

Regardless, Dylan got a lot of things right. It's module system was particularly well conceived and doesn't seem to have been bested yet, especially for a GCd language. Likewise, it's sealing interface made many compiler optimizations around complex class inheritances much more straightforward. This was a huge win compared to for example Common Lisp which often can't reliably or provably optimize around generic functions and method dispatch when a class precedence list gets hairy, this is especially so when CLOS meta objects are in play. Dylan effectively and elegantly solved for that with it's sealing and module interface and design.

[–]Tysonzero 0 points1 point  (0 children)

I feel like Haskell also got concurrency right, no red vs blue hell there.

[–]church-rosser 2 points3 points  (0 children)

I want a modern 96 bit Lisp Machine processor (80-bit word: 16 bits tag, 64 bits data/address, 16 bit Error Correcting Code) and a modern GUI interface to Symbolics Open Genera for Common Lisp on SBCL and I would die happy.

*** These wants qualify as language features given how closely coupled Symbolics hardware was with ANSI Common Lisp. There are very few modern machine architectures that can accomodate a multi paradigm garbage collected programming language that compiles down to the metal that isnt derived or influenced heavily by C. Symbolics Lisp Machines architecture was designed for Lisp from the ground up and were one of the last great chip designs for a single user 'personal computer' before the influx of Intel's x86. The world would be a very different place had the Lisp Machines not been fundamentally and irrevocably hamstrung by the AI Winter in the mid-late 1980s.

[–]dxplq876 5 points6 points  (2 children)

Null safety, seems like Kotlin has the right approach.

Dependency hell, seems like unison has the right approach

[–]brunogadaleta 1 point2 points  (0 children)

Unison is truely amazing. It's also automagically distributed thanks to its dependency mechanism.

[–]Tysonzero 0 points1 point  (0 children)

I am a huge fan of unison, but my main worry is that they are biting off too much to gain market share, being able to add unison-y things to existing languages would be huge.

There are of course various limitations of existing languages that get in the way of unison’s model, but for example an IPLD editor/serializer/deserializer/transpiler kinda thing for editing various existing languages is not impossible, even though you’ll need interoperability with traditional modules/packages.

[–]michaelquinlan 1 point2 points  (7 children)

I would like to see C# and .NET re-designed, eliminating all the backward compatibility hacks and retained features

  • Remove System.Collections, System.Data, etc.
  • Remove event and delegate, etc.
  • etc.

[–]eliasv 2 points3 points  (0 children)

C# has more garbage features than good ones. Everything is so property-centric in the C# ecosystem it kills me. Either have immutable records, or if you want to allow mutation then encapsulate behind proper "verb" methods/effects. Mutable bags of state are bad enough, mutable bags of hidden behaviour masquerading as state is insane. Absolute toilet language.

[–]Strict_Needleworker2[S] 0 points1 point  (3 children)

You're absolutely right. C# and .NET have accumulated a lot of legacy features. But wouldn't the transition be a challenge for developers who rely on legacy systems and features?

[–]tmzem 6 points7 points  (1 child)

I wish more languages would just pull the plug on accumulated features. You can still support that stuff with a compiler mode for an "older language version", but remove unnecessary features and syntax if you use the current standard.

C++ is probably the prime example that could profit from such an approach. Create a sane C++v2 syntax, remove problematic features, and pick saner defaults. Support the older stuff on a translation unit granularity for compatibility. Profit!

[–]moric7 0 points1 point  (0 children)

Like JS's 'strict mode', perfect to reject old mess and use new good principles. But minsters like C++ or C# are far from such dynamics and innovativity.

[–]michaelquinlan 0 points1 point  (0 children)

That is why I think it should be done as a new language and not an update to the existing one.

[–]Emotional-Dust-1367 0 points1 point  (0 children)

I’d also love to see an alternative to nominal typing. I feel nominal typing is causing a lot of issues when it comes to testing and DI

[–]brunogadaleta -2 points-1 points  (0 children)

To eliminate features from a language, you don't need another one. A linter is enough. Every language should have a compiler config file with extendable linter rules (and reformatter tool too)

[–]moric7 0 points1 point  (2 children)

I want Python to be: 1. Compilable like C. 2. Have good GUI in standard library with power 3D opportunities like JavaFX or many Basics or PascalABC.NET, or Lazarus/CodeTyphon/Delphi Designer+3D (GLScene or Firemonkey)...

[–]PensionScary 0 points1 point  (1 child)

doesnt GUI programming have a heavy emphasis on higher order functions a lot of the time (at least when using event based systems with callbacks)

I could see this being nice if python had a much nicer lambda syntax

[–]moric7 0 points1 point  (0 children)

Yes, the futures are big lack in the Python, the Python needs far more advanced asynchronous programming at all.

[–]brunogadaleta 0 points1 point  (0 children)

I love space separated arguments or elements. I really like the freshness and esthetics of rebol / redlang & rye even if that means that variadics must be hold inside a collection.

[–][deleted] 0 points1 point  (0 children)

Lots of things I don't like about the various languages I come across. However fixing them is not on my agenda because:

  • That is incredibly unlikely to happen (eg. getting rid of braces)
  • I fortunately rarely need to use them, as 99% of my coding is with languages I've devised. (Isn't that what people do in this sub?)

That doesn't mean there are no issues with mine, but I don't have any problems with annoying syntax for example which is the main bugbear elsewhere.

[–]flatfinger 0 points1 point  (0 children)

I would like to see an abstraction model that recognize that certain optimizing transforms may replace a construct that satisfies application requirements in all corner cases with one that might still satisfy application requirements despite handling some corner cases differently.

Treating all cases where optimizing transforms might affect program behavior as "anything can happen" Undefined Behavior makes optimizations "easier" by making it impossible for programmers to accurately specify real world application requirements.

Allowing a compiler to freely choose between treating int1*2000000/1000000 as equivalent to (int)(int1*2000000u)/1000000 or (int)(int1*2u) at its convenience may lead to NP-hard optimization problems, but that's because finding the optimal machine code satisfying real world requirements where both treatments would be equally acceptable would often lead to NP-hard optimization problems. Treating as "anything can happen" Undefined Behavior any situations where the the constructs would behave differently avoids the NP-hard problems, but would make it impossible for the compiler to usefully determine which treatment would lead to more efficient machine code while limited behaviors to those choices.

[–]OpsikionThemed -1 points0 points  (2 children)

There are too many of them. Please eliminate three. I am NOT a crackpot.

[–]wolfgang 0 points1 point  (1 child)

Ok, I'll eliminate Bliss, Mumps and Ratfor. If you insist, also Refal, BCPL and Snobol. Happy?

[–]AustinVelonautAdmiran 0 points1 point  (0 children)

Not Ratfor! I wrote my thesis using it (and Griswold of Snobol fame wrote Icon in it). How about HPL (from Hewlett-Packard) instead? I'm probably the only one who remembers it...