Hacker News new | ask | show | jobs
by jhhh 1662 days ago
I started learning D in 2012 and will echo that Andrei's book is great, and imo one of the most entertaining and informational technical books I've read. The D forum was a great example of dogfooding and the people seemed nice when I would post things.

But, I think one of the things that people seemed very happy about feature-wise that started to turn me off the language was UFCS. I don't deny that it makes the written code look more elegant but I think to me it existed as a net negative for other people who are unfamiliar with the code they are reading. There was an example someone gave years ago on reddit that was supposed to convey how clean the code to solve the problem was but it included an UFCS expression of the form 'a.b!c.d' which was sans-UFCS 'd(b!c(a))'. Trying to determine which reordering the compile would going to eventually choose seemed like more work than should be necessary for simple expression like that.

Having said all that it still might be a good choice for certain development environments and I should see whether there's a second edition of TDPL.

1 comments

UFCS is one of the most popular features. It's utility is in extending the functionality of a struct without adding member functions that would get private access, but don't need private access.

It helps keep structs small and simple, rather than becoming kitchen sinks.

I don't disagree that it can be useful (eg. from one of the other projects mentioned in the thread: https://github.com/Netflix/vectorflow/blob/master/src/vector...), and I definitely saw plenty of people that liked it. I think it existed in the same realm as a feature like lisp macros which are incredibly useful but when overused can turn the code into an inscrutable mess. The question for me was always how much the community would use or overuse them. When talking with other people it seemed like their own use of UFCS was obvious, but then again they wrote the code so of course they were going to understand it.

Without knowing any of the associated types and members how many interpretations could the prior expression 'a.b!c.d' have with UFCS and parens-less calling conventions (and any other feature that might contribute to different semantics)?

  b!(c.d)(a)
  b!(d(c))(a)
  d(b!c(a))
  d(a.b!c)
Might be more? Don't get me wrong I see the benefit. The vectorflow example I think is a good use case thought because it allows a more natural conceptualization of object -> member access -> conversion rather than having to call to!ulong(W.length) which forces the reader to start with the (pending) conversion. You get this same dataflow/conceptualization benefit in threading macros in clojure (->, ->>, etc).

Anyway, thank you for all the work you've done.

> b!(c.d)(a)

The template parameter after a ! without parentheses is always 1 token, so it's never one of the first two interpretations.

Furthermore, the point is that often when writing generic code, you're not supposed to care what the `.d` means specifically. For example, an `InputRange` is defined to have `.front`, `.empty` and `.popFront` properties. Is `.empty` a member variable, function, or constant? Doesn't matter, as long as it results in a boolean.

This does require some getting used to. A common question from newcomers is how to explicitly spell out the type in a situation like this:

  import std.algorithm;
  void main()
  {
      auto x = [10, 20, 30].map!(x => x*2);
  }
The answer is: you cannot! You know it's an `InputRange`, so you can access `.front`, `.empty`, `.popFront`, and pass it to range functions, but it's not a simple type like `int[]`.

While it's flexible, generic code is also complex. Many D standard library functions don't take a simple `string`, but a 'generic input range of a code unit'. (UTF-8, UTF-16, UTF-32). The resulting template machinery that this spawns is not pleasant to work with, so I understand your concern.

In my own D code, I often use regular arrays, foreach loops and if-statements instead of ranges, map and filter etc.

Andrei and I have come to the conclusion that many of the library functions are overly generalized.
The trick is, most newcomers aren't just bothered by auto and would like the explicit type here. What they want to do is actually pass that output into another method. And in that method they need to know the type. I mean, you could accept input range in the method, but then you are losing some typing information.