Hacker Newsnew | past | comments | ask | show | jobs | submit | schveiguy's commentslogin

Thank you for this post. I can tell you that we do appreciate comments like this, and the deficiencies you cite are many of the reasons we are rewriting phobos and druntime.

The time module "lied" seems like a straight up bug. Can you give any more details on it?


https://issues.dlang.org/show_bug.cgi?id=24446

Thanks for responding well to constructive criticism.


Wow, this was introduced in 2012!

https://github.com/dlang/druntime/pull/88


D has been fully unproprietary since 2017. https://forum.dlang.org/post/oc8acc$1ei9$1@digitalmars.com

But that's only the reference compiler, DMD. The other two compilers were fully open source (including gcc, which includes D) before that.

Fully disagree on your position that having all possibilities with one language is bad. When you have a nice language, it's nice to write with it for all things.


> Why "a"

`a` is a parameter in the lambda function `a => a.idup`.

> Why "map!"

This is definitely something that can trip up new users or casual users. D does not use <> for template/generic instantiation, we use !. So `map!(a => a.idup)` means, instantiate the map template with this lambda.

What map is doing is transforming each element of a range into something else using a transformation function (this should be familiar I think?)

FWIW, I've been using D for nearly 20 years, and the template instantiation syntax is one of those things that is so much better, but you have to experience it to understand.

> "idup" seems arbitrary

Yes, but a lot of things are arbitrary in any language.

This name is a product of legacy. The original D incarnation (called D1) did not have immutable data as a language feature. To duplicate an array, you used the property `dup`, which I think is pretty well understood.

So when D2 came along, and you might want to duplicate an array into an immutable array, we got `idup`.

Yes, you have to read some documentation, not everything can be immediately obvious. There are a lot of obvious parts of D, and I think the learning curve is low.


Thanks for the reply.

> Yes, but a lot of things are arbitrary in any language.

I disagree, but to each their own.

> Yes, you have to read some documentation, not everything can be immediately obvious.

I do not disagree, but I wanted to know the rationale behind it ("map!(a => a.idup)")!


import C is not perfect. There are pieces of C that don't map directly to D. Such as #define constants and macros.

That being said, it will make writing bindings a LOT easier, even though D already has direct binding to C functions.


dlangui and dlangide has been adopted by GrimMaple (who is on the D discord as well), and is actively being developed.


I learned how to use raylib from this youtube series, and used it to teach some homeschool kids D programming. Very nice series!


The rationale is that in a correctly written program, an Error should never be thrown. It's similar to UB in C. The compiler can assume Errors are never thrown, and so it can not worry about cleanup in nothrow functions.

But the nice thing is, it reuses the same handling mechanisms as exceptions. You don't have to create something different for handling Errors. In fact, the code that prints error stack traces and exits is the same code that handles exceptions.

Consequently, this is why you shouldn't catch them, or at least not catch them and continue. The exceptions are unittests and contract asserts, where the compiler does guarantee proper stack unwinding.


> The rationale is that in a correctly written program, an Error should never be thrown. [...] you shouldn't catch them, or at least not catch them and continue

In that case, why not just abort? Why give the user a footgun like this?


FWIW, C++'s noexcept specifier turns exceptions into aborts rather than letting them escape [1]:

> Non-throwing functions are permitted to call potentially-throwing functions. Whenever an exception is thrown and the search for a handler encounters the outermost block of a non-throwing function, the function std::terminate or std::unexpected (until C++17) is called:

Microsoft's dialect of C++ has a nothrow attribute which is purely advisory, like D's, and is now deprecated in favour of noexcept [2]:

> We recommend that all new code use the noexcept operator rather than __declspec(nothrow).

> This attribute tells the compiler that the declared function and the functions it calls never throw an exception. However, it does not enforce the directive. In other words, it never causes std::terminate to be invoked, unlike noexcept, or in std:c++17 mode (Visual Studio 2017 version 15.5 and later), throw().

Rust has panics, which by default unwind, like exceptions, but can be compiled to abort instead [3]:

> By default, when a panic occurs, the program starts unwinding, which means Rust walks back up the stack and cleans up the data from each function it encounters. However, this walking back and cleanup is a lot of work. Rust, therefore, allows you to choose the alternative of immediately aborting, which ends the program without cleaning up.

I don't believe there is any stable or planned way to declare that normal Rust functions cannot panic (so should abort instead of letting the panic escape). But there is some work towards the idea that extern "C" functions should do so [4].

[1] https://en.cppreference.com/w/cpp/language/noexcept_spec

[2] https://docs.microsoft.com/en-us/cpp/cpp/nothrow-cpp?view=ms...

[3] https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-...

[4] https://github.com/rust-lang/project-ffi-unwind/blob/master/...


If I understand, a throw in a nothrow would be used for completely unrecoverable situations? Akin to Rust’s panic!() macro?


Oof, seems I got the camelcase wrong. It's `@mustuse`

Working on updating that.

I think the reason the documentation is cryptic is because it's a library-supplied User Data Attribute that is specially recognized by the compiler. The documentation generator is having trouble with it. In code it's pretty simple:

https://github.com/dlang/druntime/blob/705fb36e5fc4d930eed85...


The only way you can be saying this is if you haven't experienced metaprogramming in D. C++ does not compare at all. Generics do not compare at all.

You can take D metaprogramming from my cold dead hands.


If you were in the authors shoes and you disliked C++ templates would you also have written off Go without trying it, though?

No argument on going from D to something else but to not know either and not even try Go is what surprises me.


Yeah I do much in C# and almost never use generics. And when I do it is almost always not what I want.

D has me fooled and I can't imagine Go choosing to go further in D's direction over C#. I feel sorry for them.


You almost never use List<T>? Dictionary<TKey, TValue>? IEnumerable<T>?


Those don't matter, because while you can't build your own in Go, the built in types provide the same functionality.


I was puzzled by strange linguistic ideas of go's designers. The reference to the English language can't justify go's syntax.


Do you have an example top of mind?


Array of bytes []byte being English, but byte array byte[] being not English.


You can use arrays as if they were individual operands, and it will expand out the loop and apply the expression to all the values (and can use optimization/vector tricks if posssible).

e.g.:

arr1[] += arr2[] / 10.0 + 5;

TBH, I don't use this feature much, because I work with ranges more than arrays, which do not have this ability. This feature predates ranges (and the std.algorithm.map function, which can do what you say as well).


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: