October 12, 2021

On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:

>

I'm brainstorming about what I'll talk about at DConf, and during a conversation with Walter I thought it might be cool to talk about:

  • Worst features implemented in a non-toy language

Go's implicit duck-typing of structs to interfaces. Things don't accidentally match a non-trivial interface, and hardly anyone wants to make an interface for a struct that some third party manages (just wrapping the struct would more idiomatic for Go). For the sake of saving a one-line inheritance specifier, this magic makes it so much harder to figure out which structs are intended to match an interface in a large codebase written by multiple people.

Supporting error detection without helping with error handling. Python is good because exceptions inherit from standard types that can be handled consistently (e.g., KeyError). Most other languages (including D) aren't much help here. Go misses the point by acting like "if err != nil { return err }" is actually handling errors.

I agree with others that C's type declaration syntax is a non-feature. It's pointlessly "clever" and not even consistent. I've blogged about this problem here: https://theartofmachinery.com/2020/08/18/d_declarations_for_c_programmers.html

I'm sure you can think of more C++ problems than me, but let me pick three that epitomise why I don't like C++ any more:

SFINAE. It's powerful, but makes template metaprogramming slow at compile time, terrible to debug and hard to read. D shows that explicit constraints are better all around.

Member function pointers. They're hard to use correctly and "feel" low level, but are actually very high level. D's delegates are easier to use and reason about, yet are lower level (NB: closures are higher level, but that's a different story).

Sensible operator overloading for a simple number-like type takes a lot of boring boilerplate, which encourages developers to do "interesting" things with operator overloading instead. D makes the sensible things easy, so there's less of a culture of "interesting" metaprogramming hacks.

>
  • Worst features (in your opinion) in D
  • The multiple (confusing) ways to write anonymous lambdas.
  • opDispatch's (lack of) error handling semantics.
  • Autodecoding.
  • Overuse of attributes. (It fills the type system with things that could be better done with separate notation for static checking tooling.)
  • Overloaded semantics of . that makes namespacing hard in practice.
  • The hacky non-virtual destructor implementation.
>
  • Features you'd like to see in D

Overall, I don't think D needs many more features. But because you asked:

  • Better value analysis to make integer promotion issues less annoying.
  • Better error handling for opDispatch.
  • Native tuple support (with destructuring, etc.).
>

Ideas? Examples?

Thanks!

October 13, 2021
On Tuesday, 12 October 2021 at 21:38:48 UTC, Timon Gehr wrote:
> On 10/11/21 5:59 PM, Atila Neves wrote:
>> ...
>
> This is likely to be incomplete or overly abstract, but here's my approximate take:
>
>> * Worst features implemented in a non-toy language
>
> - unsound type system
> - undefined behavior for categories of errors other than memory corruption
> - inappropriately nondeterministic semantics
> - mutable aliasing by default (mutability is fine, aliasing is the issue)
> - pointer arithmetic without appropriate type system support
> - imprecise type system (>40 years behind state of the art)
> - non-orthogonal language definition
> - null pointers without appropriate type system support
> - Turing-complete constructors

Please mention the language for each point. I think that "inappropriately nondeterministic semantics" can be JS.
October 13, 2021

On Monday, 11 October 2021 at 20:48:47 UTC, 12345swordy wrote:

>

On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:

> >

Worst features implemented in a non-toy language
- GC as a feature
This GC phobia is hurting the d language.

  • class (reference type)
    WHY!?

-Alex

because, as other said, it is hard to differentiate from struct (values), you always have to check the symbol signature, wich is just annoying

void pass(MyType* type) {}
void pass(MyType type) {}

you can't know what is a type or the pointer of a reference type, having to guess / context switch to go check symbol signature is a pain

October 13, 2021
On Tuesday, 12 October 2021 at 20:29:32 UTC, Paul Backus wrote:
> On Tuesday, 12 October 2021 at 19:41:57 UTC, H. S. Teoh wrote:
>> - C++ concepts-like feature of specifying the expected interface of a
>>   template parameter.
>>    - Yes, sig constraints fit the bill, kinda-sorta.  But it leads to
>>      poor, unhelpful error messages.  Yes, this can be fixed by using
>>      static if, pragma(msg), etc., but this requires a lot of extra work
>>      on the part of the user which should have been handled by the
>>      language.
>>    - Yes, there's a dub package that kinda-sorta does this. But again,
>>      this is something that should have been done by the language.
>
> You can get about 90% of the way to better constraint errors with existing language features:
>
>     struct Check
>     {
>         bool passed;
>         string message;
>
>         T opCast(T : bool)() { return passed; }
>     }
>
>     enum hasFoo(T) =
>         Check(
>         	__traits(hasMember, T, "foo"),
>             "`" ~ T.stringof ~ "` must have a member named `foo`"
>         );
>
>     struct Pass { int foo; }
>     struct Fail { int bar; }
>
>     // Can check with static assert
>     static assert(hasFoo!Pass);
>     static assert(!hasFoo!Fail);
>
>     // Works in constraints
>     auto getFoo(T)(T input)
>         if (hasFoo!T)
>     {
>         return input.foo;
>     }
>
>     static assert(__traits(compiles, Pass().getFoo));
>     static assert(!__traits(compiles, Fail().getFoo));
>
>     // Can check error message
>     pragma(msg, hasFoo!Fail.message);
>
> The only thing missing is a way to get the compiler to print out your custom message, instead of (or in addition to) the default "must satisfy `hasFoo!T`" message.
>
> I plan to write a DIP for this as soon as I am done with @nodiscard.

templates doesn't work with DCD/DSymbol because it doesn't do semantic analysis, so that kind of features is impossible implement for tooling right now..


this is why things like tagged union (sumtype) and multiple return type should be implemented as language features, that way it is easier to parse (on top of other benefits)

please push for language feature! your work on sumtype was great, but there is much more to gain from upgrading it as a language feature
October 13, 2021
On Wednesday, 13 October 2021 at 01:56:19 UTC, russhy wrote:
> this is why things like tagged union (sumtype) and multiple return type should be implemented as language features, that way it is easier to parse (on top of other benefits)
>
> please push for language feature! your work on sumtype was great, but there is much more to gain from upgrading it as a language feature

If anyone wants to work on a DIP and implementation for built-in sum types, they will have my full support. Unfortunately, I do not have the time or the skills necessary to lead such a project myself.
October 13, 2021
On Wednesday, 13 October 2021 at 02:39:47 UTC, Paul Backus wrote:
> On Wednesday, 13 October 2021 at 01:56:19 UTC, russhy wrote:
>> this is why things like tagged union (sumtype) and multiple return type should be implemented as language features, that way it is easier to parse (on top of other benefits)
>>
>> please push for language feature! your work on sumtype was great, but there is much more to gain from upgrading it as a language feature
>
> If anyone wants to work on a DIP and implementation for built-in sum types, they will have my full support. Unfortunately, I do not have the time or the skills necessary to lead such a project myself.

I think such a feature would benefit from having tuple syntax and semantics done first. Timon did have a DIP for tuples.
October 13, 2021
On Wednesday, 13 October 2021 at 01:56:06 UTC, russhy wrote:
> On Monday, 11 October 2021 at 20:48:47 UTC, 12345swordy wrote:
>> On Monday, 11 October 2021 at 18:27:29 UTC, russhy wrote:
>>>> Worst features implemented in a non-toy language
>>>     - GC as a feature
>> This GC phobia is hurting the d language.
>>> - class (reference type)
>> WHY!?
>>
>> -Alex
>
>
> because, as other said, it is hard to differentiate from struct (values), you always have to check the symbol signature, wich is just annoying

It is not an issue if you have a functional IDE that does the heavy lifting for you. This isn't a language issue here.

You are doing something very wrong if you find yourself typing
>void pass(Mytype* type) {}

where Mytype is a class. This is not c++ here.

-Alex


October 13, 2021

On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:

>
  • Worst features implemented in a non-toy language

I can't believe no one has mentioned this yet: PHP register globals. That is, the feature that creates variables in your scripts from request parameters.

>
  • Worst features (in your opinion) in D

Difficult to say, but all the half implemented features.

>
  • Features you'd like to see in D
  • Non nullable pointers and reference types by default

  • Built-in or syntax sugar for optional types

  • Native tuples with destruction and named values:

    (int, string) tup = (1, "foo");
    auto (a, b) = tup;
    
    (int, int) point = (x: 2, y: 4);
    auto x = point.x + a;
    
  • Some form of zero overhead exceptions. Example:

    struct PermissionDenied {}
    struct FileNotFound {}
    
    int open(string filename) throw(PermissionDenied, FileNotFound);
    
    string readFile(string filename) throw(auto)
    {
        auto fd = open(filename);
        // ...
    }
    
    void main()
    {
        try
            auto content = readFile("foo.txt");
        catch (PermissionDenied e) {}
        catch (FileNotFound e) {}
    }
    

    The above is lowered to:

    struct PermissionDenied {}
    struct FileNotFound {}
    
    Result!(int, PermissionDenied, FileNotFound) open(string filename);
    
    Result!(string, PermissionDenied, FileNotFound) readFile(string filename)
    {
        R0 __tmp0 = open(filename);
        int fd = void;
        switch (__tmp0.tag)
        {
            case R0.Tag.success:
                fd = __tmp0.value;
            // ...
            break;
    
            case R0.Tag.error0: return typeof(return)(__tmp0.error0);
            case R0.Tag.error1: return typeof(return)(__tmp0.error1);
        }
    }
    
    void main()
    {
        R0 __tmp0 = readFile("foo.txt");
        string content = void;
        switch (__tmp0.tag)
        {
            case R0.Tag.success:
                content = __tmp0.value;
                break;
    
            case R0.Tag.error0:
                PermissionDenied e = __tmp0.error0;
                break;
    
            case R0.Tag.error1:
                FileNotFound e = __tmp0.error1;
                break;
        }
    }
    

--
/Jacob Carlborg

October 13, 2021

On Wednesday, 13 October 2021 at 19:55:29 UTC, Jacob Carlborg wrote:

>

On Monday, 11 October 2021 at 15:59:10 UTC, Atila Neves wrote:

>

[...]

I can't believe no one has mentioned this yet: PHP register globals. That is, the feature that creates variables in your scripts from request parameters.

[...]

"Native tuples with destruction", are you sure you don't want deconstruction instead 😉

October 13, 2021
On 10/12/21 1:29 AM, surlymoor wrote:
> I just want to be able to have a returned value be implicitly wrapped if its type is part of the `SumType` returned by the function.
> 
> ```d
> // -preview=shortenedMethods is awesome
> SumType!(int, string) div(int a, int b) => b != 0 ? a : "Divisor is zero";
> ```

Hear, hear