Should this work?

Manu turkeyman at gmail.com
Thu Jan 9 17:33:35 PST 2014


On 10 January 2014 06:27, H. S. Teoh <hsteoh at quickfur.ath.cx> wrote:

> On Thu, Jan 09, 2014 at 06:25:33PM +0000, Brad Anderson wrote:
> > On Thursday, 9 January 2014 at 14:08:02 UTC, Manu wrote:
> [...]
> > >On a side note, am I the only one that finds
> > >std.algorithm/std.range/etc for string processing really obtuse?  I
> > >can rarely understand the error messages, so say it's better than STL
> > >is optimistic.
> >
> > I absolutely hate the "does not match any template declaration"
> > error. It's extremely unhelpful for figuring out what you need to do
> > and anytime I try to do something fun with ranges I can expect to
> > see it a dozen times.
>
> Yeah, that error drives me up the wall too. I often get screenfuls of
> errors, dumping 25 or so overloads of some obscure Phobos internal
> function (like toImpl) as though an end-user would understand any of it.
> You have to parse all the sig constraints (and boy some of them are
> obscure), *understand* what they mean (which requires understanding how
> Phobos works internally), and *then* try to figure out, by elimination,
> which is the one that you intended to match, and why your code failed to
> match it.
>
> I'm almost tempted to say that using sig constraints to differentiate
> between template overloads is a bad idea. Instead, consider this
> alternative implementation of toImpl:
>
>         template toImpl(S,T)
>                 // N.B.: no sig constraints here
>         {
>                 static if (... /* sig constraint conditions for overload
> #1 */)
>                 {
>                         S toImpl(T t)
>                         {
>                                 // implementation here
>                         }
>                 }
>                 else static if (... /* sig constraint conditions for
> overload #2 */)
>                 {
>                         S toImpl(T t)
>                         {
>                                 // implementation here
>                         }
>                 }
>                 ...
>                 else // N.B.: user-readable error message
>                 {
>                         static assert(0, "Unable to convert " ~
>                                 T.stringof ~ " to " ~ S.stringof);
>                 }
>         }
>
> By putting all overloads inside a single template, we can give a useful
> default message when no overloads match.
>

*THIS* .. I've always thought that, and intuitively written my D code that
way. Funnily, I was always concerned I was being unidiomatic doing so,
since the 'std' code is rarely written like that.


Alternatively, maybe sig constraints can have an additional string
> parameter that specifies a message that explains why that particular
> overload was rejected. These messages are not displayed if at least one
> overload matches; only if no overload matches, they will be displayed
> (so that the user can at least see why each of the overloads didn't
> match).
>
>
> [...]
> > >I also find the names of the generic algorithms are often unrelated
> > >to the name of the string operation.  My feeling is, everyone is
> > >always on about how cool D is at string, but other than 'char[]', and
> > >the builtin slice operator, I feel really unproductive whenever I do
> > >any heavy string manipulation in D.
>
> Really?? I find myself much more productive, because I only have to
> learn one set of generic algorithms, and I can use them not just for
> strings but for all sorts of other stuff that implement the range API.
>

That sounds good in theory, but if any time you try and actually use D's
generic algorithms you end up with many of the kind of errors you refer to
in your prior paragraph, then that basically undermines the whole
experience.
I don't like wasting my time, and I don't like pushing my way through
learning something that I feel is obtuse to begin with, so I usually take a
side path and work around it (most things can be done easily with a couple
of nested foreach-es). So, perhaps embarrassingly, despite my 3+ years
spent hanging around here, part of the problem is that I barely know/use
phobos. Call me lazy, but I don't think it's an unrealistic experience for
any end-user. If it saves me time/headache (and bloat) not using it, why
would I?
** Yes, it's the 'standard' library, and I like that concept in essence,
and feel like I should make use of it on principle... but it's like, you
need to already know phobos intimately to think it's awesome, which creates
a weird barrier to entry. And the docs don't help a lot.

Whereas in languages like C, sure you get familiar with string-specific
> functions, but then when you need a similar-operating function for an
> array of ints, you have to name it something else, and then basically
> the same algorithm reimplemented for linked lists, called by yet another
> name, etc.. Added together, it's many times more mental load than just
> learning a single set of generic algorithms that work on (almost)
> everything.
>
> The composability of generic algorithms also allow me to think on a more
> abstract level -- instead of thinking about manipulating individual
> chars, I can figure out OK, if I split the string by "," then I can
> filter for the strings I'm looking for, then join them back again with
> another delimiter. Since the same set of algorithms work with other
> ranges too, I can apply exactly the same thought process for working
> with arrays, linked lists, and other containers, without having to
> remember 5 different names of essentially the same algorithm but applied
> to 5 different types.
>

See, I get that idea about composability. Maybe it's just baggage from C,
but I just don't think that way. Maybe that's a large part of why I always
go wrong with phobos.
I would never think of doing something fundamental like string processing
with a sequence of generic algorithm. I'd freak out about the relatively
unknown performance characteristics.
Algorithms are usually a lot simpler when performed on strings of bytes
than they are performed on strings of objects with any imaginable copying
mechanisms and allocations patterns.
Unless I wrote something myself, I can never have faith that the sort of
concessions required to make it generic also make it fast in the case it
happens to be performed in a byte array.

There's an argument that you can specialise for string types, which is true
within single functions, but if you're 'composing' a function with generic
parts, then you can't specialise for strings anymore... There's no way to
specialise a call to a.b.c() as a compound operation.

Like I say, it's probably psychological baggage, but I tend to
unconsciously dismiss/reject that sort of thing without a second though...
or maybe experience learned me my lesson (*cough* STL).


> I actually feel a lot more productive in D than in C++ with strings.
> > Boost's string algorithms library helps fill the gap (and at least
> > you only have one place to look for documentation when you are using
> > it) but overall I prefer my experience working in D with
> > pseudo-member chains.
>
> I found that what I got out of taking the time to learn std.algorithm
> and std.range was worth far more than the effort invested.
>

Perhaps you're right. But I think there's ***HUGE*** room for improvement.
The key in your sentence is, it shouldn't require 'effort'; if it's not
intuitive to programmers with decades of experience, then there are
probably some fundamental design (or documentation/accessibility)
deficiencies that needs to be prioritised. How is any junior programmer
meant to take to D?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20140110/eb2ac38d/attachment-0001.html>


More information about the Digitalmars-d mailing list