April 29, 2012
Jonathan M Davis:

> * foreach_reverse is essentially redudant at this point (not to mention
> confusing if combined with delegates), since we have retro.

retro() can't replace foreach_reverse until the front-end demonstrability produces asm code equally efficient.
Loops _must_ be fully efficient, they are a basic language construct, this is very important. Even foreach() is sometimes not equally efficient as a for() in some cases...


> * I hate C style struct initializers and would really like to see them go, but
> for reasons that I don't understand, people actually use them rather than using a proper constructor call,

For single structs I prefer D-style initialization.
But take a look at this code, if you replace those C-style initializers with D-style, even using aliases to shorten the code to single letters, that data section becomes more noisy:
http://rosettacode.org/wiki/Ray-casting_algorithm#D


> * As for features that add little value, the first one that comes to mind is
> with. I think that I've used it all of once, and I don't think that I've seen
> it in other people's code very often.

It's rather common in Pascal/Delphi programming. I use it now and then.

For a case where it's very handy see here, with an enumeration:
http://rosettacode.org/wiki/Stable_marriage_problem#Alternative_version


> It's hard to grep for (since with is
> used in comments quite often),

Try to search for "with("  or "with\s(", that are less common in normal text.


> * Increasingly, I don't like UFCS. I think that in most cases, it complicates
> code for little value. And I _really_ don't like how it results in people
> flipping chains of a(b(c(d(5)))) calls into something like d(5).c().b.().a(). I
> think that it makes the code way harder to read.

For me it makes that kind of code way simpler to read...


> The code is completely backwards.

It means call d on 5, then call c on the result, then call b on the result, and then call a on the result. It's better than before :-)

Bye,
bearophile
April 29, 2012
Le 28/04/2012 20:47, Walter Bright a écrit :
> What's your list?

- builtin complex types (I don't _need_ be able to write "4 + 5i")
- builtin associative arrays
- some builtin properties like arr.sort
- lazy, I use it only for logging
- foreach_reverse, never used it
- comma operator: when do you ever need it?
- in operator


Other than that, as a user I can't say having a lot of features is a big problem, it's a major selling point.
April 29, 2012
On Sat, Apr 28, 2012 at 04:56:52PM -0700, Jonathan M Davis wrote: [...]
> One _big_ difference between D and C++ as far as complexity goes is that in C++, a _lot_ of the complexity comes from weird things in the language and knowing about how certain things can go horribly wrong (e.g. I can never remember all of the details on how horribly broken multiple inheritence is).

Ugh. C++ multiple inheritance is a labyrinth, nay, a veritable minefield of subtle tripwires, inconvenient limitations, and a source of hair-tearing headaches. It's one of the bigger problems with C++'s OO implementation. Java's idea of single inheritance, multiple interfaces is a much better concept.


> It's frequently not an issue of knowing how to do things in the language but rather an issue of knowing what weird side effects an problems happen with certain stuff. With D, on the other hand, the complexity tends to be in just knowing what all of the features are and what they can do.

Except is() expressions, which appear to be totally arbitrary to me. As far as I'm concerned, it's just "memorize these bunch of arbitrary special rules".


> The only feature that comes to mind as probably being overly complex is is expressions, but that complexity can really come in handy sometimes.  std.traits should probably do more to alleviate the need for is expressions though so that odds of needing some of the more complicated stuff are lessened.

Needing to rely on std.traits is backwards, IMO. It's the compiler that knows all this stuff about types, why should we need to consult a library to get at the information? But anyway, the *functionality* of is-expressions are very useful, and, I'd argue, necessary. It's just that the syntax is atrocious and needs fixing.


> * As for redundant features, the first one that really comes to mind is WYSIWYG string literals. There are what, 4 different types of delimiters for string literals?

Only 4? I thought there were more. Last I looked, there were like 6 separate cases.


> I don't even remember all of the options. I just always use ` if I don't want any escaping in string literal and " if I do. The others may be valuable enough to have in some contexts, but I _never_ use them.

Yeah, I agree we should merge some of the string literal syntaxes. Some of them are useful (I'm a sucker for heredoc syntax) but currently it seems like just way too many options for something that should be really straightforward.


[...]
> * I hate C style struct initializers and would really like to see them go, but for reasons that I don't understand, people actually use them rather than using a proper constructor call, so I doubt that we could get rid of them without a fair bit of complaining. I think that they're completely redundant and very _un_D.

It's annoying to have to write a constructor whose only purpose is to copy arguments into field members. Many uses of structs don't need the encapsulation that ctors were intended for.


> * There seem to be too many ways to do variadic functions. We have to allow C style variadics for extern(C), but having 3 of our own seems like a bit much.  Variadic templates are generally all that we need. The others don't seem necessary for the most part. But unfortunately, they should probably be left in so that classes can use them with virtual functions, since they can't use templates.

IMO we should unify variadic syntax into one (or perhaps leave the C variadics separate, since they're just for compatibility with C), and let the compiler implement each appropriately for the given context.


[...]
> * Increasingly, I don't like UFCS. I think that in most cases, it
> complicates code for little value. And I _really_ don't like how it
> results in people flipping chains of a(b(c(d(5)))) calls into
> something like d(5).c().b.().a(). I think that it makes the code way
> harder to read. The code is completely backwards. But I appear to be
> in the minority with that opinion. I also don't like how it creates so
> many ways to write exactly the same code. It harms readibility. But as
> much as I dislike many of the applications of UFCS, it _does_ appear
> to be quite popular. And upon occasion, it may be useful, but I _am_
> wishing that we hadn't added it.

Strange, I like it a lot because unifying function calls makes it very easy to write generic code without sprinkling static ifs everywhere.


[...]
> Overall, I think that D's feature set is fairly solid. It's mostly just the implementation of said features which is a problem - though some minor tweaks are probably in order (e.g. as Bearophile suggests, make it so that adjacent string literals don't concatenate).
[...]

I thought adjacent string lits have been deprecated or no longer supported? Personally I like it; it lets you format long literals over multiple lines without needing a ~ in between. And also, recently I found this annoyance:

	throw new Exception("A very long message (%s) that is "~
		"broken across multiple (%d) lines".format(msg,count));

This doesn't work because ~ has lower precedence than ., so you need extra parentheses around the strings:

	throw new Exception(("A very long message (%s) that is "~
		"broken across multiple (%d) lines").format(msg,count));

Whereas being able to concatenate adjacent literals would've been this a lot more readable.


T

-- 
I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller
April 29, 2012
H. S. Teoh:

> It's annoying to have to write a constructor whose only purpose is to copy arguments into field members.

This is not needed in D for structs. Try it.


> I thought adjacent string lits have been deprecated or no longer
> supported?

Walter accepted to deprecate it lot of time ago, but it's not implemented yet.


> Personally I like it; it lets you format long literals over multiple lines without needing a ~ in between.

If you write an array literal with many strings inside, and you forget a comma, you get less strings, silently. This is a source of real bugs. C# too disallows this, I think.


> And also, recently I found this annoyance:

Right, the precedence of the ~ operator different from the precedence of the invisible space operator. This causes some disadvantages. But I think the advantages in gained correctness are more important.

Bye,
bearophile
April 29, 2012
On Saturday, April 28, 2012 18:24:20 H. S. Teoh wrote:
> > * I hate C style struct initializers and would really like to see them go, but for reasons that I don't understand, people actually use them rather than using a proper constructor call, so I doubt that we could get rid of them without a fair bit of complaining. I think that they're completely redundant and very _un_D.
> 
> It's annoying to have to write a constructor whose only purpose is to copy arguments into field members. Many uses of structs don't need the encapsulation that ctors were intended for.

You don't have to. If you have

struct S
{
    int field1;
    float field2;
    string field3;
}

then you can do

auto s = S(5, 7.2, "hello");

The ability to do

S s = {5, 7.2, "hello"};

gains you _nothing_.

- Jonathan M Davis
April 29, 2012
On Sunday, 29 April 2012 at 01:06:54 UTC, bearophile wrote:
>> * I hate C style struct initializers and would really like to see them go, but
>> for reasons that I don't understand, people actually use them rather than using a proper constructor call,
>
> For single structs I prefer D-style initialization.
> But take a look at this code, if you replace those C-style initializers with D-style, even using aliases to shorten the code to single letters, that data section becomes more noisy:
> http://rosettacode.org/wiki/Ray-casting_algorithm#D

 I have one source file called staticdata.d; Here immutable global data is stored. It's literally pages and pages of data and i only using static this() when building an AA.

//excerpt: /NP and VT aliases.
immutable SubRecordParts subParts[] = [
	{"AADT", "", 16, [		//alchemy (apparatus)
		NP(VT.ranged_32, "Apparatus"),
		NP(VT.float_32, "Quality"),
		NP(VT.float_32, "Weight"),
		NP(VT.i_32, "uses")]},		
	{"AODT", "", 24, [		//armor
		NP(VT.ranged_32, "Armor Body Type"),
		NP(VT.float_32, "Weight"),
		NP(VT.i_32, "Value"),
		NP(VT.i_32, "Health"),
		NP(VT.i_32, "Enchant Points"),
		NP(VT.i_32, "Armour")]},	
	{"BKDT", "", 20, [		//book
		NP(VT.float_32, "Weight"),
		NP(VT.i_32, "Value"),
		NP(VT.i_32, "isScroll"),
		NP(VT.ranged_32, "Skill ID"),
		NP(VT.i_32, "Enchantment points")]}];

 Would you really force me to use fully named and qualified for every element? More verbose but helps not at all.

immutable SubRecordParts subParts[] = [
	SubRecordParts("AADT", "", 16, [		//alchemy (apparatus)
		NotePart(ValueType.ranged_32, "Apparatus"),
		NotePart(ValueType.float_32, "Quality"),
		NotePart(ValueType.float_32, "Weight"),
		NotePart(ValueType.i_32, "uses")]),		
	SubRecordParts("AODT", "", 24, [		//armor
		NotePart(ValueType.ranged_32, "Armor Body Type"),
		NotePart(ValueType.float_32, "Weight"),
		NotePart(ValueType.i_32, "Value"),
		NotePart(ValueType.i_32, "Health"),
		NotePart(ValueType.i_32, "Enchant Points"),
		NotePart(ValueType.i_32, "Armour")]),	
	SubRecordParts("BKDT", "", 20, [		//book
		NotePart(ValueType.float_32, "Weight"),
		NotePart(ValueType.i_32, "Value"),
		NotePart(ValueType.i_32, "isScroll"),
		NotePart(ValueType.ranged_32, "Skill ID"),
		NotePart(ValueType.i_32, "Enchantment points")])
	];
April 29, 2012
On Sunday, April 29, 2012 03:06:53 bearophile wrote:
> > * Increasingly, I don't like UFCS. I think that in most cases,
> > it complicates
> > code for little value. And I _really_ don't like how it results
> > in people
> > flipping chains of a(b(c(d(5)))) calls into something like
> > d(5).c().b.().a(). I
> > think that it makes the code way harder to read.
> 
> For me it makes that kind of code way simpler to read...
> 
> > The code is completely backwards.
> 
> It means call d on 5, then call c on the result, then call b on the result, and then call a on the result. It's better than before :-)

I know that you find easier to read. A number of people do. But it is just so backwards in comparison to how stuff normally works, that it hurts my brain. But I've done enough functional programming that I find something likea(b(c(d(5)))) to be completely straightforward, and for some reason not everyone does. And while I _never_ intend to use UFCS in this manner, I'm going to forever have to read the code of others who do, which I find to be a major negative.

But regardless of my personal opinion on the matter, it's clear that enough people like UFCS that it's not going anywhere unless something seriously wrong is found with it which makes it untenable.

- Jonathan M Davis
April 29, 2012
On Sunday, 29 April 2012 at 01:36:10 UTC, Jonathan M Davis wrote:
> On Saturday, April 28, 2012 18:24:20 H. S. Teoh wrote:
> then you can do
>
> auto s = S(5, 7.2, "hello");
>
> The ability to do
>
> S s = {5, 7.2, "hello"};
>
> gains you _nothing_.

 Depends on how many levels you are using on a array. I've noted in another part of this topic where I have pages and pages of the data. Forcing me to qualify it with a name when the compiler/structure already knows just seems like an annoyance. True it removes the {}'s, but I think I have 3 levels of deep.

 S[] s = [S(),S(),S()];

 vs

 S[] s = [{},{},{}];

 If they are more complex, then indenting and separation makes sense. And the size of the name I don't want to have to Alias my structures to something tiny and a little obfuscate in order to keep it compact and simple. That's my thoughts anyways. If the language later disallows it, I'll have to change my code to compensate for it.
April 29, 2012
On 4/29/12, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> struct S
> {
>     int field1;
>     float field2;
>     string field3;
> }
> then you can do
>
> auto s = S(5, 7.2, "hello");
>
> The ability to do
>
> S s = {5, 7.2, "hello"};
>
> gains you _nothing_.

That's not really the benefit of those initializers. This is:

S[] arr = [{field2 = 1.0}, {field2 = 0.5}];

It's a real benefit when unittesting because it allows me to quickly create variables with some interesting state which I can then test.
April 29, 2012
> - properties - another incredibly convenient feature. I think a more sexy implementation of properties are in order, but the construct is great. It would be nice to have properties as a language type, rather than a attribute:

To me, properties are much more than a convenience. The important part of it comes from its existence, not its usage. Quite simply, having properties mean that using public member variables does not break encapsulation (as long as having them part of the public interface is intentional).

Without properties, you MUST write accessors for all of them on the off chance that you might want to refactor/delegate them in the future. This adds a huge amount of boilerplate code that ends up wasted time 98% of the time.

In short, properties existing, even if not used, end up improving both my efficiency and the legibility of my code.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18