Worst ideas/features in programming languages?

Timon Gehr timon.gehr at gmx.ch
Sun Nov 14 23:05:03 UTC 2021


On 14.11.21 22:54, Dr Machine Code wrote:
> On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
>> On 10/11/21 5:59 PM, Atila Neves wrote:
>>> ...
>> ...
>>
>>> * Features you'd like to see in D
>>
>> - built-in tuples/products with standard syntax

auto (a,b) = (1,2);

(int a, string b) = fetch!((x)=>(1,text(x)));

[(1,2),(3,4)].map!((a,b)=>a+b).each!writeln;

>> - built-in tagged unions/sums,

Not sure about detailed syntax, maybe something like:

(int+string) x = inj(0,1);
(int+string) y = inj(1,"hi");

> nullable,

Maybe:

int*? x=null;
writeln(*x); // error

if(x) writeln(*x); // ok

C? x = ...;
D? = x?.method();

> algebraic data types

Maybe:

enum Result(T){
     Ok(T),
     Error(string)
}

>> - pattern matching

auto x = match(r){
     Ok(0) => 3;
     Ok(x) => x+1;
     Error(_): assert(0);
}

int toInt((int+string) x)
    match(x){
        (0, x): return x;
        (1, s): return to!int(s);
    }
}

>> - real support for linear/affine typing

auto x = S();
auto y = move(x);
auto z = x; // error: undefined identifier x
auto y = move(y); // ok

// error: y was not explicitly moved away or destroyed

>> - named parameters with support for perfect forwarding and 
>> compile-time introspection

void foo(int x=0,int y=0,int z=0;

foo(x: 100, z: 200);

auto apply(alias f,T...)(T args){ return f(args); }

apply!foo(x: 100, z: 200);

>> - built-in duck-typed record types playing nice with named parameters

auto r = (x: 100, z: 200);
foo(r);

>> - type classes / some standard way to add UFCS methods to a type from 
>> another module that are then visible in an instantiated template from 
>> a third module

import a: S;
import b: rangeFun;

auto ref front(ref S s){ ... }
bool empty(ref S s){ ... }
void popFront(){ ... }

void main(){
     S s;
     rangeFun(s with(front, empty, popFront));
     alias T=S with (front,empty,popFront);
     T t=s;
     rangeFun(t);
}

>> - uniform syntax for function definition, in particular `int add(int 
>> a,int b)=>a+b;` (-preview=shortenedMethods)

int add(int a,int b)=>a+b;

>> - `let Statement in Expression` expression

void main(){
     auto z = {
         int x=1;
         int y=2;
     } in x+y;
     assert(z==3);
}

>> - `Expression where Statement` expression
> ...

void main(){
     auto z = x+y where{
         int x=1;
         int y=2;
     };
     assert(z==3);
}

> could you give example what those would be like?
> ...

See above. Unfortunately I only had time to give some contrived examples.

>> - mixin identifiers
> example?

static foreach((name, value);[("x",1),("y",2),("z",3)]){
     int mixin(name) = value;
}

writeln(x," ",y," ",z); // 1 2 3

>> - __local, static break and continue
> what would __local do?
> ...

static foreach(i;0..100){
     __local alias X=Foo!(T[i]); // local to static foreach, does not 
clash between iterations
     mixin Bar!X;
}

>> (https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1010.md)

Also see the explanation in the DIP.

>> - template literals
> example?

enum sizes = staticMap!((B)!=>B.sizeof,Types);

>> - static opIndex/opSlice
>> - AST introspection
>> - consistent treatment of operators for built-in types, e.g. 
>> 1.opBinary!"+"(2) should work.
>> - operator overloading should combine orthogonally with UFCS
>> - better support for subtyping (expose the concept to user-defined 
>> types, e.g., Range!(const(T)) could be a subtype of const(Range!T)) 
>> and any other features required to support a good container library
>> - async/await (or similar)
>> - yield (or similar)
>> - range literals
> what's that?

auto b = (fun(x) for x in iota(100) if bar(x));

// equivalent to:
// auto b = iota(100).filter!(x=>bar(x)).map!(x=>fun(x));

>> - more lightweight coroutines
>> - ProtoObject
>> - special treatment of qualified types, in particular qualified 
>> reference types (e.g. `immutable` classes should allow conversion of 
>> references from `immutable` to mutable)
>> - non-deterministic semantics, with as little undefined behavior as 
>> possible, in particular for type/function qualifiers
>> - compile-time fixed-point support (e.g., with struct S(T){ T* next; 
>> }, fix!S gives a singly linked list).
>> - flow-sensitive typing
> what's that?

class A{ void foo(){ ... } }
class B:A{ void bar(){ ... } }

void foo(A a){
     if(a is B){
         B b=a; // ok
         a.bar(); // ok
     }
}

>> - strong variable updates (probably not happening)
> what's that?

int x=2;
x="123";
static assert(is(typeof(x)==string));

auto f=File(x,"r");
static assert(is(typeof(f)==File));
f.close();
static assert(is(typeof(f)==ClosedFile));

>> - non-lexical variable lifetimes (probably not happening)
>> - parametric polymorphism, in particular for type qualifiers (probably 
>> not happening)
>> - some amount of dependent types (dreaming now)
> 
> you got very nice features, are you making DIPs for those?
> 

I started this:
https://github.com/tgehr/DIPs/blob/tuple-syntax/DIPs/DIP1xxx-tg.md
https://github.com/tgehr/dmd/commits/tuple-syntax

Unfortunately, I was too busy at the time to finish the implementation, 
and I am not fully satisfied with the proposal. Probably I'd want to add 
at least static opIndex and static opSlice to it. Another issue is that 
it slightly expands `alias this` and I am not sure whether that's a 
direction Walter is willing to invest in at this point.


More information about the Digitalmars-d mailing list