View mode: basic / threaded / horizontal-split · Log in · Help
March 20, 2012
Re: Three Unlikely Successful Features of D
On 3/20/2012 3:58 PM, Nick Sabalausky wrote:
> Alias in particular is a much bigger deal than it seems since it's seemingly
> trivial but can be *incredibly* helpful with templates *and* with importing.

I'd have to agree with this. I find it amazing that other languages entirely 
miss the boat on this.

C++ has a very crippled version of it in "template template parameters".
March 20, 2012
Re: Three Unlikely Successful Features of D
On Tue, 20 Mar 2012, Don wrote:

> On 20.03.2012 21:33, Don wrote:
> > * pragma(msg) is something that's been used 100X as often as anticipated.
> 
> Note that because it was so successful, it was incorporated into static
> assert.

I wrote the original msg part of assert and static assert.  It wasn't 
because of pragma(msg), it was because I wanted a message with my asserts. 
:)

Later,
Brad
March 20, 2012
Re: Three Unlikely Successful Features of D
On Tue, Mar 20, 2012 at 06:58:31PM -0400, Nick Sabalausky wrote:
> - Type inference

Yeah I forgot about this one. Being able to write:

	auto veryLongNamedObject = new VeryLongNamedClass(veryLongArguments);

is a big boon over C++ or Java's stuttering verbosity:

	VeryLongNamedClass veryLongNamedObject = new VeryLongNamedClass(veryLongArguments);

Plus, it's immensely useful when dealing with Range templates... can you
imagine the horrifically long typenames you'd have to type you have to
explicitly specify the type of a long chain of functional expressions
involving 15+ std.algorithm and std.range templates?


> - alias

This, together with static ifs and templates, make for awesome tricks
involving templates that would've been an utter bear to pull off in C++.

	template innerKeyType(T) {
		static if (is(T U : U[K], K))
			alias innerKeyType!K innerKeyType;
		else
			alias T innerKeyType;
	}
	innerKeyType!(int[string[char[byte]]]) innerKey;


[...]
> - Built-in associative arrays that support nearly any type as a key

This is actually quite buggy right now... but that's merely an
implementation issue. :-)  My new AA implementation, for example,
already correctly supports AA's with AA keys, which can be arbitrarily
nested. So you could have something like int[string[char[byte]]], and it
does lookups correctly based on the contents of the AA's you pass in as
key.


> - All the niceities of ctors compared with C++'s ctors

C++ ctors are a royal pain in the neck. I remember in the early days of
C++ when you can still call the base class ctor in the body of the
derived class ctor... nowadays you have to contort ctor code into a
horrible ugly mess just to get your ctor to do things right. Plus, the
C++ standard requires fields to be initialized in declaration order,
which is needlessly restrictive and basically makes ctors even more of a
pain.

I ended up using just stub ctors for a lot of my code, and doing the
actual initialization after the object is constructed. Which is very bad
OO style, I agree, but the pain of working with C++ ctors just pushes me
in the wrong direction, y'know?


> - Scope guards (And even finally: I head somewhere C++ doesn't even have 
> finally: Is that true?!?)

Yes, it's true. I don't know about C++11, but certainly the previous
standard has no finally clause, leading to horribly unmaintainable and
ugly code like:

	Resource r = acquireResource();
	try {
		doSomethingDangerous();
	} catch(...) {
		r.release();
	}
	r.release();

(Yes, yes, I know, RAII and all that... which leads to inventing
ridiculous classes which make no sense in terms of OO, just to wrap
resource handles.)


> - GC

For all the warts the current GC has, the fact that D has a GC at all
makes things like array slicing possible, and *fast*, which leads to all
the other niceties of slicing.


> - Name any of D's metaprogramming features
[...]
> Alias in particular is a much bigger deal than it seems since it's
> seemingly trivial but can be *incredibly* helpful with templates *and*
> with importing.

Definitely. Using alias and static if in a recursive template is one of
the hallmarks of the awesomeness of D templates.


> Actually, looking at this list, I'm now starting to get a little worried 
> about an upcoming C++ project... No doubt I'll be trying to reinvent a lot 
> of D in it. Probably in ugly hackish ways.
[...]

#include "dmd.h"

;-)


T

-- 
Don't modify spaghetti code unless you can eat the consequences.
March 21, 2012
Re: Three Unlikely Successful Features of D
What you might want to do is look back at
early ng posts about features and see which
ones were met with "meh", but universally
considered to rok now.

Asking for stuff now will be hard to be
unbiased on the surprise issue.


If my memory serves, a few things that were
"meh" when announced but that rok now are:

1) enum. I remember an argument over if we
should call it invariant, manifest, or the
relatively unpopular enum keyword, but I
don't recall people at the time expecting
it to be as useful as it is now.

The argument was between

manifest MY_VALUE = 1;
and
enum MY_VALUE = 1;

without thoughts along the line of:

template octal(...) {
    alias octalImpl(t) octal;
}

or most the other stuff we use ctfe with now.


(Speaking of octal, I remember that being dismisses
as a "hack" by some members too. Now, it looks like
that pattern is catching on for user defined literals,
and it rox.)


My memory might be bad, but looking at some old posts
could confirm if the "unlikely success" label is warranted.




2) Leaving the parenthesis off of simple template
instantiations is something I was against early on,
and now I love it.

IIRC, you wanted to use a different symbol entirely,
and leaving the parens off was a compromise between
the radical Unicode character proposal and Walter's
conservative parenthesis.



This is a really small change. At the time, it seemed
like it would be stupid and useless.



But, would templates be as popular now if we didn't
make this change?

auto a = to!(int)("10");

vs

auto a = to!int("10");



to!int feels like one word, unlike to!(int)().
Who needs atoi when we can say to!int?


Decls too: Appender!int, etc. The popularity of
this in phobos and outside speaks to a success
I didn't expect.



3) My mind is coming up blank on a third newsgroup argument
over an awesome feature we use now. But, something I
am often amazed about is how cool structs are.

When you say "struct", I used to think of "whoo a collection
of vars, big deal".

But, now, with D2, when you say "struct", I think "fully
customizable powerhouse".

(even coming from C++, where much of this can be done, D's
structs are still a little mindblowing in comparison.)
March 21, 2012
Re: Three Unlikely Successful Features of D
On Wednesday, 21 March 2012 at 00:53:19 UTC, Adam D. Ruppe wrote:
> template octal(...) {
>     alias octalImpl(t) octal;
> }

LOL, I was bloviating about "enum" and ended up
using "alias" here.

alias rox too (which is a bit amazing, considering how
simple it is), but I should have said:

enum octal = octalImpl(t);
March 21, 2012
Re: Three Unlikely Successful Features of D
> There are a few features of D that turned out to be successful, 
> in spite of them being seemingly unimportant or diverging from 
> related consecrated approaches.
>
> What are your faves?

After thinking some time about this, I can't find one of them :-)
I see many useful/successful features in D, but none of them
seemed unimportant at first to me.

Maybe I am just strange, but very little of syntax and semantics
of a language is unimportant. In languages even unused features
(C trigraphs?) sometimes bite your bum, so they become important,
with negative value.

Bye,
bearophile
March 21, 2012
Re: Three Unlikely Successful Features of D
"Walter Bright" <newshound2@digitalmars.com> wrote in message 
news:jkb2v6$kq4$2@digitalmars.com...
> On 3/20/2012 3:58 PM, Nick Sabalausky wrote:
>> Alias in particular is a much bigger deal than it seems since it's 
>> seemingly
>> trivial but can be *incredibly* helpful with templates *and* with 
>> importing.
>
> I'd have to agree with this. I find it amazing that other languages 
> entirely miss the boat on this.
>
> C++ has a very crippled version of it in "template template parameters".

I particulary love how D's alias is used to disambiguate symbol conflicts. 
Brilliant approach. I know I wouldn't have thought of it.
March 21, 2012
Re: Three Unlikely Successful Features of D
On Tuesday, 20 March 2012 at 19:02:16 UTC, Andrei Alexandrescu 
wrote:
> I plan to give a talk at Lang.NEXT 
> (http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012) with 
> the subject above. There are a few features of D that turned 
> out to be successful, in spite of them being seemingly 
> unimportant or diverging from related consecrated approaches.
>
> What are your faves? I have a few in mind, but wouldn't want to 
> influence answers.
>
>
> Thanks,
>
> Andrei

I've seen most of D's cool features mentioned, but I believe 
nobody mentioned mixins yet. Mixins are messy to maintain, but 
together with CTFE they can be used to create some really neat 
code if used properly.

One of the first things I wrote while learning D is a vector 
class. In GLSL vectors can be 'swizzled', for example:
vec3(1, 2, 3).zyx == vec3(3, 2, 1);
Swizzles are often useful in graphics or physics code. I don't 
know of any non-shading language that allows me to use swizzle 
syntax. As the following code shows, it's quite easy to do in D:


module main;

import std.stdio;
import std.process;
import std.conv;


int main(string[] argv) {
  alias Vec!4 Vec4;
  Vec4 v = Vec4(1, 2, 3, 4);

  writeln(v.bgra); // Prints Vec!(4)([3, 2, 1, 4])
  writeln(v.rg); // Prints Vec!(2)([1, 2])

  return 0;
}

private immutable (char[][]) elementNames = [['x', 'y', 'z', 
'w'], ['r', 'g', 'b', 'a'], ['s', 't', 'p', 'q']];

struct Vec(size_t size) {
  alias size Size;

  mixin(generateConstructor(Size));

  mixin(generateProperties(Size));

  auto opDispatch(string s)() {
    mixin(generateSwizzle(s));
  }

  float v[Size];
}

private string generateConstructor(size_t size) {
  string constructorParams;
  string constructorBody;

  foreach(i; 0..size) {
    string paramName = "v" ~ to!string(i);
    constructorParams ~= "float " ~ paramName ~ "=0,";
    constructorBody ~= "v[" ~ to!string(i) ~ "] = " ~ paramName ~ 
";";
  }

  return "this(" ~ constructorParams[0..$-1] ~ "){" ~ 
constructorBody ~ "}";
}

private string generateProperties(size_t size) {
  string props;

  foreach(names; elementNames) {
    foreach(i, name; names[0..size]) {
      props ~= "@property float " ~ name ~ "() const { return v[" 
~ to!string(i) ~ "]; }";
      props ~= "@property void " ~ name ~ "(float f) { v[" ~ 
to!string(i) ~ "] = f; }";
    }
  }

  return props;
}

private string generateSwizzle(string elements) {
  string swizzleImpl = "return Vec!" ~ to!string(elements.length) 
~ "(";

  foreach(e; elements) {
    swizzleImpl ~= e ~ ",";
  }

  return swizzleImpl[0..$-1] ~ ");";
}
March 21, 2012
Re: Three Unlikely Successful Features of D
And there goes the formatting, here's a pastebin version:
http://pastebin.com/dHdiG0ce

On Wednesday, 21 March 2012 at 01:41:27 UTC, Rene Zwanenburg 
wrote:
> On Tuesday, 20 March 2012 at 19:02:16 UTC, Andrei Alexandrescu 
> wrote:
>> I plan to give a talk at Lang.NEXT 
>> (http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012) 
>> with the subject above. There are a few features of D that 
>> turned out to be successful, in spite of them being seemingly 
>> unimportant or diverging from related consecrated approaches.
>>
>> What are your faves? I have a few in mind, but wouldn't want 
>> to influence answers.
>>
>>
>> Thanks,
>>
>> Andrei
>
> I've seen most of D's cool features mentioned, but I believe 
> nobody mentioned mixins yet. Mixins are messy to maintain, but 
> together with CTFE they can be used to create some really neat 
> code if used properly.
>
> One of the first things I wrote while learning D is a vector 
> class. In GLSL vectors can be 'swizzled', for example:
> vec3(1, 2, 3).zyx == vec3(3, 2, 1);
> Swizzles are often useful in graphics or physics code. I don't 
> know of any non-shading language that allows me to use swizzle 
> syntax. As the following code shows, it's quite easy to do in D:
>
>
> module main;
>
> import std.stdio;
> import std.process;
> import std.conv;
>
>
> int main(string[] argv) {
>   alias Vec!4 Vec4;
>   Vec4 v = Vec4(1, 2, 3, 4);
>
>   writeln(v.bgra); // Prints Vec!(4)([3, 2, 1, 4])
>   writeln(v.rg); // Prints Vec!(2)([1, 2])
>
>   return 0;
> }
>
> private immutable (char[][]) elementNames = [['x', 'y', 'z', 
> 'w'], ['r', 'g', 'b', 'a'], ['s', 't', 'p', 'q']];
>
> struct Vec(size_t size) {
>   alias size Size;
>
>   mixin(generateConstructor(Size));
>
>   mixin(generateProperties(Size));
>
>   auto opDispatch(string s)() {
>     mixin(generateSwizzle(s));
>   }
>
>   float v[Size];
> }
>
> private string generateConstructor(size_t size) {
>   string constructorParams;
>   string constructorBody;
>
>   foreach(i; 0..size) {
>     string paramName = "v" ~ to!string(i);
>     constructorParams ~= "float " ~ paramName ~ "=0,";
>     constructorBody ~= "v[" ~ to!string(i) ~ "] = " ~ paramName 
> ~ ";";
>   }
>
>   return "this(" ~ constructorParams[0..$-1] ~ "){" ~ 
> constructorBody ~ "}";
> }
>
> private string generateProperties(size_t size) {
>   string props;
>
>   foreach(names; elementNames) {
>     foreach(i, name; names[0..size]) {
>       props ~= "@property float " ~ name ~ "() const { return 
> v[" ~ to!string(i) ~ "]; }";
>       props ~= "@property void " ~ name ~ "(float f) { v[" ~ 
> to!string(i) ~ "] = f; }";
>     }
>   }
>
>   return props;
> }
>
> private string generateSwizzle(string elements) {
>   string swizzleImpl = "return Vec!" ~ 
> to!string(elements.length) ~ "(";
>
>   foreach(e; elements) {
>     swizzleImpl ~= e ~ ",";
>   }
>
>   return swizzleImpl[0..$-1] ~ ");";
> }
March 21, 2012
Re: Three Unlikely Successful Features of D
"H. S. Teoh" <hsteoh@quickfur.ath.cx> wrote in message 
news:mailman.933.1332286692.4860.digitalmars-d@puremagic.com...
> On Tue, Mar 20, 2012 at 06:58:31PM -0400, Nick Sabalausky wrote:
>> - Type inference
>
> Yeah I forgot about this one. Being able to write:
>
> auto veryLongNamedObject = new VeryLongNamedClass(veryLongArguments);
>
> is a big boon over C++ or Java's stuttering verbosity:
>
> VeryLongNamedClass veryLongNamedObject = new 
> VeryLongNamedClass(veryLongArguments);
>
> Plus, it's immensely useful when dealing with Range templates... can you
> imagine the horrifically long typenames you'd have to type you have to
> explicitly specify the type of a long chain of functional expressions
> involving 15+ std.algorithm and std.range templates?
>
>
>> - alias
>
> This, together with static ifs and templates, make for awesome tricks
> involving templates that would've been an utter bear to pull off in C++.
>
> template innerKeyType(T) {
> static if (is(T U : U[K], K))
> alias innerKeyType!K innerKeyType;
> else
> alias T innerKeyType;
> }
> innerKeyType!(int[string[char[byte]]]) innerKey;
>
>

Yea, C++'s STL *needs* type inference and alias. At least the new spec has 
"auto". Don't know about other stuff though.


> [...]
>> - Built-in associative arrays that support nearly any type as a key
>
> This is actually quite buggy right now... but that's merely an
> implementation issue. :-)

Heck, I just love that I can use a string, or an int, or make my own struct 
work as a key, etc. Actually, over just the last 24 hours I've been making a 
lot of use of AAs with int keys. (AA's make it *so* much easier to avoid 
poor time complexity in a lot of things.)

Many langauges (like Haxe, for example) will have hashtables, and may even 
have them templated (or otherwise generic) on *value*, but the keys will be 
string-only. Which is still very useful, but it also misses out on many 
other use-cases.

> My new AA implementation, for example,
> already correctly supports AA's with AA keys, which can be arbitrarily
> nested. So you could have something like int[string[char[byte]]], and it
> does lookups correctly based on the contents of the AA's you pass in as
> key.
>

Crazy stuff :)

Actually I've been meaning to ask what the main benefits of your new AA 
implementation are. I know there's the benefit of just simply having it be 
implemented in the library. And you mention using AA's as AA keys here. Are 
there any other, umm, "key" points?

>
>> - All the niceities of ctors compared with C++'s ctors
>
> C++ ctors are a royal pain in the neck. I remember in the early days of
> C++ when you can still call the base class ctor in the body of the
> derived class ctor... nowadays you have to contort ctor code into a
> horrible ugly mess just to get your ctor to do things right. Plus, the
> C++ standard requires fields to be initialized in declaration order,
> which is needlessly restrictive and basically makes ctors even more of a
> pain.
>
> I ended up using just stub ctors for a lot of my code, and doing the
> actual initialization after the object is constructed. Which is very bad
> OO style, I agree, but the pain of working with C++ ctors just pushes me
> in the wrong direction, y'know?
>

Yea, that's what I've been planning on doing with the C++ stuff I have 
coming up. Don't even want to bother with C++'s ctor limitations. Just make 
an init() member and be done with it. Actually, that seems to be turning 
into more and more of a common C++ idiom though, from what (little) I've 
seen.

>
>> - Scope guards (And even finally: I head somewhere C++ doesn't even have
>> finally: Is that true?!?)
>
> Yes, it's true. I don't know about C++11, but certainly the previous
> standard has no finally clause, leading to horribly unmaintainable and
> ugly code like:
>
> Resource r = acquireResource();
> try {
> doSomethingDangerous();
> } catch(...) {
> r.release();
> }
> r.release();
>

Haxe also lacks finally! Which I always found rediculous. So yea, I'm 
intimately familiar with that idiom. I've used it myself far more than I 
would like.

And even *that* still doesn't work if you don't catch *every* exception (and 
then rethrow the ones you don't care about? Ick!). I've seen C++ programmers 
swear off exceptions because of this, and I can't blame them at all. 
Exception systems *need* a finally.

> (Yes, yes, I know, RAII and all that... which leads to inventing
> ridiculous classes which make no sense in terms of OO, just to wrap
> resource handles.)
>

Yea, if I wanted to write Java-style code, I'd just use Java (and at least 
not have to deal with header files).

>
>> - GC
>
> For all the warts the current GC has, the fact that D has a GC at all
> makes things like array slicing possible, and *fast*, which leads to all
> the other niceties of slicing.
>

I used to do indie game dev in C/C++ and I feel downright spoiled now with 
tossing in a "new" whenever appropriate and not have to worry about cleanup 
(and even that wouldn't be *too* bad...in certain cases...if there were at 
least scope guards).

>
>> - Name any of D's metaprogramming features
> [...]
>> Alias in particular is a much bigger deal than it seems since it's
>> seemingly trivial but can be *incredibly* helpful with templates *and*
>> with importing.
>
> Definitely. Using alias and static if in a recursive template is one of
> the hallmarks of the awesomeness of D templates.
>

I'd say one of the hallmarks of D's metaprogramming is the enormous 
*decrease* in the need for recursive templates in the first place ;) With 
C++'s templates, it would appear that you have to use recursion and helper 
templates for damn near anything.

>
>> Actually, looking at this list, I'm now starting to get a little worried
>> about an upcoming C++ project... No doubt I'll be trying to reinvent a 
>> lot
>> of D in it. Probably in ugly hackish ways.
> [...]
>
> #include "dmd.h"
>
> ;-)
>

Heh, yea. :)

>
> -- 
> Don't modify spaghetti code unless you can eat the consequences.

Hah! :)
1 2 3 4 5 6 7
Top | Discussion index | About this forum | D home