12 ms·
Features of D That I Love
- Alifatisk 1y agoI like D, it's fascinating and powerful language. It made it even more curious when I watched Tsodings video on D. One thing that came to my mind when reading the article is that things like int.init instead of 0 and $ as shorthand for array.length does add to the mental load. One good memory I had is a couple of years ago when I built a little forum using D. Man the site was blazing fast, like the interaction was instant. Good times.
- WalterBright 1y agoThe `.init` is there because the default initializer isn't always 0.
- fuzztester 1y agoforum.dlang.org is also written in D.
- gallier2 1y ago.init is not necessarily 0. For int it is, but for float it's NaN. For char it's 255 and for an enum, it's whatever you have decided it is. enum thing { first = -1, second, etc. } This way, a variable of type thing has -1 as init value.
- OskarS 1y agoThe "invariants" thing is fantastic, I haven't seen anything like that before and it's great. The C++26 contract stuff is fine, but this seems like a really great way of ensuring type invariants, I think I'd use this way more if it was in C++.
- almostgotcaught 1y ago> Invariants are functions that run at the start and end of every public member function these are just runtime assertions EDIT: how am i getting downvoted for copy-pasting literally what the article verifies?
- jayd16 1y agoI think there's something to be said about them running automatically that is lost when you say they're just asserts.
- almostgotcaught 1y agoi don't get it - if do int foo(int a) { assert(a > 5); int b = a * 10; assert(b > 50); return b; } do you think those asserts don't "run automatically"?
- gblargg 1y agoYou define the invariants once for the class and they are run around every public function. Done manually you'd probably use a helper object that calls the invariants in its constructor and destructor (have to handle exceptions) that you have to add to every public function's definition.
- readthenotes1 1y agoMaybe it's the editorial "just"? Like: software programs can't be that difficult to create properly because they are just 1s and 0s.
- johnisgood 1y agoThis is not the first time someone getting down-voted for using the word "just". I do not know if this really is warranted, however.
- LorenDB 1y agoYes, but they are guaranteed to run at the beginning and end. C/C++ asserts need to handle any return path, whereas D has functionality to mark statements to run at the end of any return path while only being written once. See also the scope(exit) feature.
- 1y ago
- destructionator 1y agoJust a personal anecdote, Walter Bright's Digital Mars C++ compiler also had the contracts (D started life almost literally as recycled code from Mr. Bright's other compilers - he wrote a native Java compiler, a Javascript 1.3 stdlib, and a C++ compiler with a bunch of extensions.... smash those together and you have the early D releases!). Anyway, I used the DM C++ compiler originally because it was the only one I could download to the high school computers without filling out a form, and pimply-face youth me saw "DESIGN BY CONTRACT" at the top of the website and got kinda excited thinking it was a way to make some easy money coding online. Imagine my disappointment when I saw it was just in/out/invariant/assert features. (I'm pretty sure D had just come out when I saw that, but I saw `import` instead of `#include` and dismissed it as a weenie language. Came back a couple years later and cursed my younger self for being a fool! lol)
- WalterBright 1y agoThe in/out features come into their own when inheritance is in play, i.e. for member functions of classes and interfaces. See https://dlang.org/spec/function.html#in_out_inheritance https://dlang.org/spec/function.html#in_out_inheritance `import` is so cool we extended it to be able to import .c files! The D compiler internally translates them to D so they can be used. When this was initially proposed, the reaction was "what's that good for?" It turned out to be incredibly useful and a huge time saver. The concept is sort of like C++ being a superset of C and so being able to incorporate C code, except unlike C++, the C syntax can be left behind. After all, don't we get tired of: struct Tag { ... } Tag; ?
- 1718627440 1y ago> struct Tag { ... } Tag; What's the thing with the syntax? If you don't intend to use the type elsewhere don't give it a tag, if you want, you have to give it a name. (Assuming you are annoyed by the duplicate Tag)
- WalterBright 1y agoWhich would you prefer: struct Tag { ... } or: typedef struct Tag { ... } Tag; ? It's just simpler and easier to write code in D than in C/C++. For another example, in C/C++: int foo(); int bar() { return foo(); } int foo() { return 3; } The D equivalent: int bar() { return foo(); } int foo() { return 3; }
- deleted 1y ago[deleted]
- 12_throw_away 1y agoYeah, these look excellent. Am curious if D's invariants can be traced back to Ada/Spark at all (I don't know much about Ada except that it has these sorts of safety features).
- johnisgood 1y agoMaybe this might help: https://news.ycombinator.com/item?id=44449835 https://news.ycombinator.com/item?id=44449835
- peterashford 1y agoI think they were introduced with Eiffel, which was all about design by contract
- johnisgood 1y agoAda has that too, for what it is worth: https://learn.adacore.com/courses/intro-to-ada/chapters/contracts.html https://learn.adacore.com/courses/intro-to-ada/chapters/cont... and https://en.wikibooks.org/wiki/Ada_Programming/Contract_Based_Programming https://en.wikibooks.org/wiki/Ada_Programming/Contract_Based.... It can be verified at compile time. But what I love the most is: https://news.ycombinator.com/item?id=43936007 https://news.ycombinator.com/item?id=43936007 Instead of: const MIN_U32 = 0; const MAX_U32 = 2 ** 32 - 1; function u32(v) { if (v < MIN_U32 || v > MAX_U32) { throw Error(`Value out of range for u32: ${v}`); } return leb128(v); } You can do this, in Ada: subtype U32 is Interfaces.Unsigned_64 range 0 .. 2 ** 32 - 1; or alternatively: type U32 is mod 2 ** 32; and then you can use attributes such as: First : constant U32 := U32'First; -- = 0 Last : constant U32 := U32'Last; -- = 2 ** 32 - 1 Range_ : constant U32 := U32'Range; -- Range 0 .. 2**32 - 1 Does D have anything like this? Or do any other languages?
- discardable_dan 1y agoThe issue is most developers do not bother to write any, and the ones that are written are most-often vapid typing failures ("these`int`s cannot be negative" should be handled by a type). I studied this field in grad school, and the entire problem almost always devolves into convincing developers to engage with the system.
- fuzztester 1y ago>The "invariants" thing is fantastic, I haven't seen anything like that before and it's great. is it not the same as the one in Eiffel?
- vbezhenar 1y agoI feel like this feature could be implemented on top of more universal features. Checking input parameters is easy, just write asserts at the start of the function. Checking result requires "destructor" block and some kind of accessible result variable, so you can write asserts in this destructor block which you can place at the start of the function, as well. Checking class invariants requires a way to specify that some function should be called at the end of every public function. I think, it's called aspect-oriented programming in Java and it's actually useful for more things, than just invariant checking. Declarative transaction management, logging. There are probably two schools of programming language designs. Some put a lot of features into language and other trying to put a minimal number of features into language which are enough to express other features.
- sirwhinesalot 1y agoHaving the higher level abstraction built into the language gives extra semantic meaning that can be taken advantage of to build tooling. For example, one could build a symbolic model checker based on the contract specifications. It would be possible to do the same with the lower level features, but a lot harder if they aren't used consistently and correctly. Same reason function calls are better than arbitrary jumps.
- deleted 1y ago[deleted]
- pjmlp 1y agoSee Design By Contract, and the language that brought its ideas into mainstream, Eiffel. What D or C++26 can do, is a subset of Eiffel capabilities, or more modern approaches like theorem proving in tools like Ada/SPARK, Dafny, FStar,...
- scrubs 1y agoBeat me to it. Eiffel et al have been at the party for a while now.
- eric-p7 1y agoIt's a mystery why D isn't far more popular than it is. Fast compilation, familiar syntax, and supports a wider range of programming paradigms than most (any?) other language.
- nickpp 1y agoLack of large “sponsors”.
- zem 1y agoscala is probably the poster child for supporting every paradigm you might want to use :) oz/mozart has more but that was essentially a research/teaching language specifically designed to use a wide range of paradigms in order to demonstrate them.
- Imustaskforhelp 1y agoCan you please specify more to be honest. This comment really catched my eye and maybe has pushed me to trying out scala but like my issue is that everywhere it says that scala primarily works good for OOP but like I know it can do functional too. I am not sure if what supporting every paradigm is a definitely good thing though I feel like I would love the freedom to do so. I am a tinkerer at heart/first and a coder at second and my favourite language is probably go and then nim/julia/elixir/typescript/<it depends on the project>
- zem 1y agoscala is intended to provide full support for both functional and object oriented programming. the positive side is that it will support programming in whatever style you like, or any mix in of styles. the negative side is that it is a huge language with a complex type system, and that the library ecosystem has a mix of various styles, e.g. there is scalaz which is heavily inspired by more purely functional languages like haskell, and scalaz code will look totally bizarre to you if you have mainly been using the object oriented features of scala. (contrast with go, which is on the opposite end of the spectrum in that a design goal is that go code should look familiar no matter where you see it, because the language supports a very constrained style of programming)
- mamcx 1y agoI don't use D but think that error handling is one major feature: https://dlang.org/articles/exception-safe.html https://dlang.org/articles/exception-safe.html In concrete, looks to me to be the only language that covers the major ways to do it. (In concrete the `scope` way is the one I found inspiring. . I think the exceptions can go and be replace by it for langs where exceptions are removed)
- WalterBright 1y ago`scope` is very good at its job. It guarantees that a pointer passed as an argument does not escape the caller's scope. I find it almost as useful as transitive `const`.
- elcritch 1y ago> Syntax - UFCS (Uniform Function Call Syntax) UFCS is such an underrated language feature. When you have UFCS you can toss out 90% of the uses of methods in favor of just plain ole functions. Add generic functions and concepts and you rarely end up needing OO support.
- jayd16 1y agoIf all you're doing is accessing public members, sure.
- WalterBright 1y agoIt works for all functions that have parameters, `f(a)` and `a.f()` are equivalent.
- jayd16 1y agoYes, but I presume that f() cannot access private members of a.
- WalterBright 1y agoThat's correct.
- nicwilson 1y ago`private` is only private to the module, not the struct/class, (In other words, all functions in the same module are all C++ style `friend`s) and so free function in same module work.
- layer8 1y agoDot syntax tends to work better for code completion, though. In addition, without uniform call syntax, adding a new method can only break subclasses, whereas with uniform call syntax it can break other client code.
- 1y ago
- azhenley 1y agoI really enjoy these lists of interesting features from various languages. They pop up occasionally on HN but now I can’t find them (Hillel Wayne had multiple). I want a meta list of all these interesting features across languages. EDIT: I found one! “Micro features I’d like to see in more languages” https://buttondown.com/hillelwayne/archive/microfeatures-id-like-to-see-in-more-languages/ https://buttondown.com/hillelwayne/archive/microfeatures-id-...
- throwawaymaths 1y ago$ operator. great idea! i believe the only contender is julia (with "end" but that is a SUUPER awkward keyword since end also closes functions) > Structs and classes can even overload this operator nope. fuck, now it's a terrible idea
- bachmeier 1y agoI don't see why it would be a terrible idea. It's pretty convenient if you're slicing a multidimensional array.
- throwawaymaths 1y agoexcept are you sure that's what it's doing? it could have been overloaded. you have to ask yourself that every time.
- Doxin 1y agoOr you can assume it's implemented sanely. Yes if someone overrides $ and does something wildly wrong with it that'll get confusing. That's the fault of whoever wrote that code though, not of $ itself. You can also overload +, imagine the mayhem if someone did something weird with that. should we ban overloading operators altogether?
- throwawaymaths 1y ago> Or you can assume it's implemented sanely excuse me, have you spent any time in tech? people fucking love to do clever shit that gets people in trouble. using NULL as a not-pointer value signalling absence (without safeguards) is probably the most notorious -- but at least useful, but if you want to get brain meltingly annoying and pervasive, we dont have to stray too far from the idea of operator overloading; c++'s << operator can just go to hell.
- Doxin 1y agoI work in tech full time. I mostly write python code. Python similar to D allows you to override ~all operators. I have yet to run into an instance where someone has overridden operators to do something completely insane. Honestly the weirdest real use-case I've ran into is pathlib overriding division on path objects to instead mean concatenation. Which seems confusing until you realize it just means paths get written like `build_dir = root_dir / "build"` which is sensible enough. Weirdest not-real use case is of course the famous goto-in-python module which overrides attribute access in combination with unhinged dark magic to implement goto.
- jadbox 1y agoHas anyone compared D and Zig? I originally learned D over one weekend and then went on to completed several code competitions- the ergonomics of D are just fantastic.
- ImPleadThe5th 1y agoI was wondering the same thing. I have done a few toy projects in Zig, but found some of the docs lacking when you start to get into the weeds.
- zzo38computer 1y agoIn my opinion, some features of D are good, but I do not like all of them. CTFE is good. I do not really like the UFCS; if you want it to be used like a member of the first parameter then you should define it as a member of the first parameter (possibly as a inline function that only calls the freestanding function with the same name, if that is what you want it to do). (You could use a macro to do this automatically if you want to.) Scoped imports is good, but I think that scoped macros would also be helpful. Exhaustive switch seem like it might be better if designed differently than it is, but the idea seems to be not bad, in general.
- LorenDB 1y agoUFCS is a bit overreaching but I think it's great for its intended use of chaining expressions on ranges and such.
- destructionator 1y agothat actually wasn't its intended use; that's a side effect. The original intended use came from Effective C++ by Scott Meyers: "Prefer non-member non-friend functions to member functions.". It was meant to make that as syntactically appealing as the members.
- Doxin 1y agoHonestly the main reason UFCS is good is when you don't "own" the type your function would need to be a member of. Most common one I run into is the "to" function from the stdlib. You can do this: import std.conv; int foo=3; string bar = foo.to!string But now lets say you want to convert ints to MyCustomInts? You can hardly attach a new "to" member to int, but with UFCS it's easy. Just declare a to function anywhere in scope: MyCustomInt to(T)(T v) if(is(T==int)){ return MyCustomInt.from_int_value(v) // or however you actually do the conversion } and it'll magically work: int foo=3; MyCustomInt bar = foo.to!MyCustomInt;
- burnt-resistor 1y agoInvariants, dependent typing, and refinement types FTW. In Rust land, it really need integration of something like flux into the language or as a gradually-compatible layer. Can't have safe software without invariant checking, and not just stopping at bounds checking.
- tealpod 1y agoD is one of the most beautiful and very efficient language. I wonder why it never got the attention it deserves.
- bachmeier 1y agoInteresting that there's nothing on there about C interop (likely reflecting the use cases of the author). D does it all: ImportC (compile C code), BetterC (make a D library part of a C program), and easy C interop in both directions.
- kwoff 1y agoDlang always makes me think of two things: Walter Bright, resident of Hacker News. And awesome games I played on Linux in the 2000s: https://en.wikipedia.org/wiki/ABA_Games https://en.wikipedia.org/wiki/ABA_Games
- sirwhinesalot 1y agoAll wonderful features. Design by Contract in particular is massively underused in mainstream languages.
- randomNumber7 1y agoWhen I last looked at D they did a lot of interesting stuff with compile time function execution and s.th. like dependent types that they hacked into the language. Can someone give me an update about the current state of this?
- WhereIsTheTruth 1y agoI am an avid fan of D, but they seriously need to massively invest into tooling The current LSP is _that_ bad, it doesn't even recognize most notable D features such as templates and named arguments.. This should be their #1 priority, as the language is starting to get steam again, they should not miss tat opportunity I know Walter does not use that kind of tools, but that's becoming a requirement nowadays for young developers Please, invest into tooling!
- skocznymroczny 1y agoCan you actually have proper tooling with templates based language? I think just like C++, how much effort goes into IDEs and still they are subpar. Because with templates, the code doesn't exist until you compile it, so at best you can catch templates instantiations during compile time and then add them to the autocomplete, but anything more advanced than that is not really possible.
- WhereIsTheTruth 1y agoOdin have a great LSP, it supports everything the language offers, generics, unions, bitsets, using, same with Zig, their LSP supports most of the notable features even comptime..Both language are quite new, relatively to D There is no excuse for D, if they can make a great compiler, they surely can make great tooling too I suggest you give the D LSP a try, I have mentioned templates, but it's very frail for everything else, using `auto`, having a chain of identifiers or even using reference/pointers is enough to confuse it, most of the time I think it stems from the fact that both Zig/Odin provide a parser/lexer as part of their std, making it easier to just focus on building the tools, the community built parser is not good and lags behind
- WalterBright 1y agoThe D lexer and parser can be used standalone.
- trikko 1y agoThe only missing thing is a big sponsor. mozilla -> rust google -> go, kotlin ... n/a -> dlang
- coldtea 1y agoNot the D I expected from reading the title (come on, a low effort joke now and then is ok, if not for anything else, as an counter-example)
- p0nce 1y agoStrangely my favourite feature after 18 years of D programming (!) is that could place keywords largely in the order you like. It is strangely liberating to be able to put: pure nothrow @nogc: or pure: nothrow: @nogc: or pure nothrow @nogc { block } Sometimes this helps readability.
- quietbritishjim 1y agoAm I missing something? Those three keywords are literally in the same order in all the examples.
- p0nce 1y agoSorry, those keywords work in block like those, or relatively to a single function, in any order.
- Joker_vD 1y ago> Invariants are functions that run at the start and end of every public member function, and can be used to ensure that the type is always in a valid state. The ironic thing about this is that it means that the public functions of an object can't, generally, call each other willy-nilly unless they take special precautions: very often, the object's invariants are broken when the execution is in a middle of the object's method. This is not a problem with D, the language merely helps you to uncover this lurking problem which usually simply goes unnoticed until something breaks and someone notices it.
- WalterBright 1y agoYes, a subtle but very important point!
- DLoupe 1y agoFor me, D failed to replace C++ because of lack of design. It is more a mix of great features. But once you start learning the details simple things can get very complicated. For example, function arguments can be "in", "out", "inout", "ref", "scope", "return ref" - and combinations. Another example is conditional compilation. Great when used sparely, but can otherwise make it very difficult to understand how the code flows. In the end, reading the source code of the standard library convinced me against it. (The source code for the C++ standard library is much worse, of course).
- troupo 1y ago> For example, function arguments can be "in", "out", "inout", "ref", "scope", "return ref" - and combinations. Reminds me of "In case you forgot, Swift has 217 keywords now" https://x.com/jacobtechtavern/status/1841251621004538183 https://x.com/jacobtechtavern/status/1841251621004538183
- sfpotter 1y agoI think it's a great mix of features. I agree it would make sense to separate the wheat from the chaff, but if you're a mature adult, you should be able to decide which features are useful to you and figure a dialect that works. In general, the design of the standard library is much less alien and baroque than the STL, and is more battries-included, so you spend much less time puzzling over incantations and more time writing code. The code you have at the end is also much more concise and readable. Likewise, because D is in a lot of ways "C++ with fewer problems and papercuts", I spend way less time figuring out totally inscrutable C++ compilation errors. Consequently, I can spend more of time writing code and thinking about how to use all D's nice features to better effect. Plus, given how fungible and malleable the language is, it doesn't take a lot of effort to rework things if I want to change them in the future. Personally, I think this is the main reason D hasn't caught on. It's selling point is that it's pragmatic and doesn't shove a lot of dogma or ideology down your throat. This isn't sexy and there's nothing to latch onto. There are many styles you can write D code in... MANY more than C++: Python-style, C#-style, C++-style, C-style... hell, bash style, MATLAB-style, R style, whatever you want. But for some of these styles, you have to build the tools! The fact that all of this is possible is the result of combining one very practical and ergonomic programming language, with a thousand different QOL improvements and handy tools... plus top tier metaprogramming. IMO, the major thing holding D back right now is also along the same lines. It offers pragmatism and practicality, but the tooling is still weak. Languages like C++, Rust, and Python totally outclass D when it comes to tooling... but you have to sacrifice flexibility and ergonomics for baroque madness (C++) or BDSM (Rust) or slow and impossible to maintain code (Python). The choice is yours, I guess!
- RcouF1uZ4gsC 1y agoThe reason that D did not replace C++, IMO is garbage collection. D was so far ahead of C++98 that it wasn't funny, but garbage collection kept it from being able to be used in the same niche. D has gotten less dependent on garbage collection but C++11 (and then 17, 20, 26 (reflection)) have closed the gap enough that it is not the quantum leap that it once was.
- skocznymroczny 1y agoI hope some day D gets some WASM story going. Right now the support is very limited, pretty much only through the C subset of D which defeats the point. Supposedly the GC was the main issue, but other GC enabled languages are already thriving in the Web (Go, Java, C#). There were some efforts to enable D on the web but it seems like these are mostly one man efforts that implement only the minimum features that their specific projects required.