I don't mean to put words in the Tango crew's mouths, but IMO this piece
from 0.99.8's changelog is a great demonstration of what's wrong with D's
sloppy "accessor" syntax:
-------------
tango.time
* TimeSpan.seconds(ulong), etc. is now replaced by
TimeSpan.fromSeconds(ulong), etc. The original form causes problems when
people write code like:
auto ts = TimeSpan.seconds(60);
ts.seconds = 30; // you would think this would assign 30 seconds to ts, but
what it does is create a
// temporary and throw it away.
-------------
The fact that D lets you freely switch between "foo(x)" and "foo = x" (at
least when you're not using a return value from foo) implies that passing
one argument to a function is, in the general case, conceptually related to
assigning a value. And that is an absurdity and abuse of syntax on the same
level as pretending that string concatenation is an "addition" or that
outputting is a "<<", etc.
And this "solution" that Tango was forced to use as a result of that kludge
doesn't totally solve the problem since it leaves symantic gibberish like
this as perfectly-compileable:
ts.fromSeconds = 30; // WTF is that supposed to mean?!? But it compiles
anyway!

I don't mean to put words in the Tango crew's mouths, but IMO this piece
from 0.99.8's changelog is a great demonstration of what's wrong with D's
sloppy "accessor" syntax:
-------------
tango.time
* TimeSpan.seconds(ulong), etc. is now replaced by
TimeSpan.fromSeconds(ulong), etc. The original form causes problems when
people write code like:
auto ts = TimeSpan.seconds(60);
ts.seconds = 30; // you would think this would assign 30 seconds to ts,
but
what it does is create a
// temporary and throw it away.
-------------
The fact that D lets you freely switch between "foo(x)" and "foo = x" (at
least when you're not using a return value from foo) implies that passing
one argument to a function is, in the general case, conceptually related
to
assigning a value. And that is an absurdity and abuse of syntax on the
same
level as pretending that string concatenation is an "addition" or that
outputting is a "<<", etc.
And this "solution" that Tango was forced to use as a result of that
kludge
doesn't totally solve the problem since it leaves symantic gibberish like
this as perfectly-compileable:
ts.fromSeconds = 30; // WTF is that supposed to mean?!? But it compiles
anyway!

I feel the problem here is that you can access a type's static members
through an instance of it, not so much the property syntax.
One could argue that auto foo = TimeSpan.seconds = 30; looks weird, but
writing weird code is in no way dependent on property syntax.
--
Simen

One could argue that auto foo = TimeSpan.seconds = 30; looks weird, but
writing weird code is in no way dependent on property syntax.

True, but a function's/class's/data-member's interface shouldn't help
facilitate weird code. The creator of the function/class/data-member knows
the semantics of whatever interface they're creating, so *they* are the
proper ones who should have to choose between function syntax and property
syntax, *not* the user of the interface.

I feel the problem here is that you can access a type's static members
through an instance of it, not so much the property syntax.
One could argue that auto foo = TimeSpan.seconds = 30; looks weird, but
writing weird code is in no way dependent on property syntax.

Perhaps static being accessible from the instance is a problem, but you
can easily work around the problem by making the function's name
clearer by adding a verb. If you had:
auto foo = TimeSpan.createFromSeconds = 30;
it'd still look strange, sure, but the intent would still be pretty
clear. So in short functions that perform an action should have a verb.
--
Michel Fortin
michel.fortin michelf.com
http://michelf.com/

I don't mean to put words in the Tango crew's mouths, but IMO this
piece from 0.99.8's changelog is a great demonstration of what's wrong
with D's sloppy "accessor" syntax:
-------------
tango.time
* TimeSpan.seconds(ulong), etc. is now replaced by
TimeSpan.fromSeconds(ulong), etc. The original form causes problems
when people write code like:
auto ts = TimeSpan.seconds(60);
ts.seconds = 30; // you would think this would assign 30 seconds to
ts, but
what it does is create a
// temporary and throw it away.
-------------
The fact that D lets you freely switch between "foo(x)" and "foo = x"
(at least when you're not using a return value from foo) implies that
passing one argument to a function is, in the general case,
conceptually related to assigning a value. And that is an absurdity
and abuse of syntax on the same level as pretending that string
concatenation is an "addition" or that outputting is a "<<", etc.
And this "solution" that Tango was forced to use as a result of that
kludge doesn't totally solve the problem since it leaves symantic
gibberish like this as perfectly-compileable:
ts.fromSeconds = 30; // WTF is that supposed to mean?!? But it
compiles anyway!

One option would be to only allow that fn = v syntax where fn returns void.

ts.fromSeconds = 30; // WTF is that supposed to mean?!? But it
compiles anyway!

One option would be to only allow that fn = v syntax where fn returns
void.

That still doesn't plug all the holes. Just because a function takes one
argument and returns void still doesn't necessarily imply that it does
something that could be reasonably considered "setting".
---------
Stdout.formatln = "Hello"; // Still doesn't make much sense
---------
class Foo
{
// Complex set of private data members here
void MutateFooInPlace(bool optionA)
{
// Do some sort of fancy in-place mutation of Foo
// "optionA" is some sort of algorithm-adjusting option.
}
}
auto f = new Foo();
f. MutateFooInPlace = false; // Even worse!
---------

A bit off topic, but what's so good about that coding style anyway?
I still think that readibilty and maintability is enhanced by coding ...
// Set all to same value
a = 42;
b = 42;
c = 42;
or even ...
// Set all to c's value
c = 42;
b = c;
a = c;
--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell

I've been known to use it now and then if there's a few variables I'm
initing to the same value (assuming of course that the whole point is for
the variables to start out at the same value). It's certainly not a huge
improvement, but I see nothing wrong with it.

I don't mean to put words in the Tango crew's mouths, but IMO this
piece from 0.99.8's changelog is a great demonstration of what's wrong
with D's sloppy "accessor" syntax:
-------------
tango.time
* TimeSpan.seconds(ulong), etc. is now replaced by
TimeSpan.fromSeconds(ulong), etc. The original form causes problems
when people write code like:
auto ts = TimeSpan.seconds(60);
ts.seconds = 30; // you would think this would assign 30 seconds to
ts, but
what it does is create a
// temporary and throw it away.
-------------
The fact that D lets you freely switch between "foo(x)" and "foo = x"
(at least when you're not using a return value from foo) implies that
passing one argument to a function is, in the general case,
conceptually related to assigning a value. And that is an absurdity
and abuse of syntax on the same level as pretending that string
concatenation is an "addition" or that outputting is a "<<", etc.
And this "solution" that Tango was forced to use as a result of that
kludge doesn't totally solve the problem since it leaves symantic
gibberish like this as perfectly-compileable:
ts.fromSeconds = 30; // WTF is that supposed to mean?!? But it
compiles anyway!

One option would be to only allow that fn = v syntax where fn returns void.

Obscure rule and a bad idea in general. This way you can't do "a = b = c =
42;"-style chaining.

One option would be to only allow that fn = v syntax where fn returns
void.

c = 42;"-style chaining.

I'd say that chaining example would be a bad idea anyway. strange things
would start happening if b or c altered the value or returned a different
type. One option, if you insist on chaining working, would be to restrict
it to void returns and have the expression evaluate to the RHS.

I feel the problem here is that you can access a type's static members
through an instance of it, not so much the property syntax.

That didn't even occur to me. That's certainly a problem too.

Yes, that was my main beef with the compiler when I had to fix it. I'd
prefer static member functions not be callable on instances. On the other
hand, accessing static members is sometimes convenient:
ReallyReallyLongStructName n;
n = n.init;
Note that even with the poposed fix, this is valid code which makes for
much confusion:
TimeSpan.fromSeconds = 30;
Which essentially does nothing, but looks like it's setting a static
property.
I agree with you that the designer of a class should be the one to define
its interface, not the user. I've always wished for the ability to
specify which functions should be properties and which ones should not.
BTW, I think the way C# properties work with chaining is to do this:
// a b c are properties
a = b = c = 42;
translates to:
set_c(42);
set_b(get_c());
set_a(get_b());
-Steve

I feel the problem here is that you can access a type's static members
through an instance of it, not so much the property syntax.

That didn't even occur to me. That's certainly a problem too.

Yes, that was my main beef with the compiler when I had to fix it. I'd
prefer static member functions not be callable on instances. On the other
hand, accessing static members is sometimes convenient:
ReallyReallyLongStructName n;
n = n.init;

int x = 5;
writefln(x.init); // prints 0; how is that possible?
It should certainly be either disallowed or yield 5.
int x = 5;
writefln(typeof(x).init); // 0 as expected
Now this one is fine.

Note that even with the poposed fix, this is valid code which makes for
much confusion:
TimeSpan.fromSeconds = 30;
Which essentially does nothing, but looks like it's setting a static
property.
I agree with you that the designer of a class should be the one to define
its interface, not the user. I've always wished for the ability to
specify which functions should be properties and which ones should not.
BTW, I think the way C# properties work with chaining is to do this:
// a b c are properties
a = b = c = 42;
translates to:
set_c(42);
set_b(get_c());
set_a(get_b());
-Steve

I feel the problem here is that you can access a type's static members
through an instance of it, not so much the property syntax.

That didn't even occur to me. That's certainly a problem too.

Yes, that was my main beef with the compiler when I had to fix it. I'd
prefer static member functions not be callable on instances. On the
other
hand, accessing static members is sometimes convenient:
ReallyReallyLongStructName n;
n = n.init;

int x = 5;
writefln(x.init); // prints 0; how is that possible?

Because init is a static member of the type. x.init is equivalent to
int.init.
If you want a different default, I think you do something like:
typedef int myint = 5;
myint x;
writefln(x.init); // prints 5

It should certainly be either disallowed or yield 5.
int x = 5;
writefln(typeof(x).init); // 0 as expected
Now this one is fine.

yeah, that works, but I don't like it as much. I suppose it wouldn't be
horrible to use typeof(x) everywhere you need static data, but it does
make things much nicer, especially when you have things like enums or
constants to just access them.
-Steve