digitalmars.D - D's "accessors" are like abusing operator overloads
- "Nick Sabalausky" <a a.a> Mar 27 2009
- "Simen Kjaeraas" <simen.kjaras gmail.com> Mar 27 2009
- "Nick Sabalausky" <a a.a> Mar 27 2009
- "Nick Sabalausky" <a a.a> Mar 27 2009
- Michel Fortin <michel.fortin michelf.com> Mar 27 2009
- BCS <none anon.com> Mar 27 2009
- "Nick Sabalausky" <a a.a> Mar 27 2009
- Derek Parnell <derek psych.ward> Mar 27 2009
- "Nick Sabalausky" <a a.a> Mar 27 2009
- "Denis Koroskin" <2korden gmail.com> Mar 27 2009
- BCS <none anon.com> Mar 27 2009
- "Steven Schveighoffer" <schveiguy yahoo.com> Mar 27 2009
- "Denis Koroskin" <2korden gmail.com> Mar 27 2009
- "Steven Schveighoffer" <schveiguy yahoo.com> Mar 27 2009
- Jarrett Billingsley <jarrett.billingsley gmail.com> Mar 27 2009
- "Denis Koroskin" <2korden gmail.com> Mar 27 2009
- Christopher Wright <dhasenan gmail.com> Mar 27 2009
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!
Mar 27 2009
On Fri, 27 Mar 2009 09:09:27 +0100, Nick Sabalausky <a a.a> wrote: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
Mar 27 2009
"Simen Kjaeraas" <simen.kjaras gmail.com> wrote in message news:op.urfzx0ia1hx7vj biotronic-pc.osir.hihm.no...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.
Mar 27 2009
"Simen Kjaeraas" <simen.kjaras gmail.com> wrote in message news:op.urfzx0ia1hx7vj biotronic-pc.osir.hihm.no...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.
Mar 27 2009
On 2009-03-27 04:45:26 -0400, "Simen Kjaeraas" <simen.kjaras gmail.com> said: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/
Mar 27 2009
Hello Nick,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.
Mar 27 2009
"BCS" <none anon.com> wrote in message news:a6268ff401a8cb7cd0afe22784 news.digitalmars.com...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! ---------
Mar 27 2009
On Fri, 27 Mar 2009 18:57:50 +0300, Denis Koroskin wrote:This way you can't do "a = b = c = 42;"-style chaining.
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
Mar 27 2009
"Derek Parnell" <derek psych.ward> wrote in message news:b3ttq8dh6euj.6tg6gfg6kfnj.dlg 40tude.net...On Fri, 27 Mar 2009 18:57:50 +0300, Denis Koroskin wrote:This way you can't do "a = b = c = 42;"-style chaining.
A bit off topic, but what's so good about that coding style anyway?
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.
Mar 27 2009
On Fri, 27 Mar 2009 18:53:51 +0300, BCS <none anon.com> wrote:Hello Nick,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.
Mar 27 2009
Hello Denis,On Fri, 27 Mar 2009 18:53:51 +0300, BCS <none anon.com> wrote: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.
Mar 27 2009
On Fri, 27 Mar 2009 13:44:48 -0400, Nick Sabalausky <a a.a> wrote:"Simen Kjaeraas" <simen.kjaras gmail.com> wrote in message news:op.urfzx0ia1hx7vj biotronic-pc.osir.hihm.no...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
Mar 27 2009
On Fri, 27 Mar 2009 21:56:36 +0300, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 27 Mar 2009 13:44:48 -0400, Nick Sabalausky <a a.a> wrote:"Simen Kjaeraas" <simen.kjaras gmail.com> wrote in message news:op.urfzx0ia1hx7vj biotronic-pc.osir.hihm.no...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
Mar 27 2009
On Fri, 27 Mar 2009 15:13:16 -0400, Denis Koroskin <2korden gmail.com> wrote:On Fri, 27 Mar 2009 21:56:36 +0300, Steven Schveighoffer <schveiguy yahoo.com> wrote:On Fri, 27 Mar 2009 13:44:48 -0400, Nick Sabalausky <a a.a> wrote:"Simen Kjaeraas" <simen.kjaras gmail.com> wrote in message news:op.urfzx0ia1hx7vj biotronic-pc.osir.hihm.no...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 5It 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
Mar 27 2009
On Fri, Mar 27, 2009 at 3:13 PM, Denis Koroskin <2korden gmail.com> wrote:int x = 5; writefln(x.init); // prints 0; how is that possible? It should certainly be either disallowed or yield 5.
In DMD pre-1.017, it would print 5. The language spec was changed with that version.
Mar 27 2009
On Fri, 27 Mar 2009 22:37:39 +0300, Jarrett Billingsley <jarrett.billingsley gmail.com> wrote:On Fri, Mar 27, 2009 at 3:13 PM, Denis Koroskin <2korden gmail.com> wrote:int x = 5; writefln(x.init); // prints 0; how is that possible? It should certainly be either disallowed or yield 5.
In DMD pre-1.017, it would print 5. The language spec was changed with that version.
Yeah, I know, but still uneasy with the spec change.
Mar 27 2009
Nick Sabalausky wrote: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:
I agree, it's a hack. I really enjoy using properties, too, but I think C# has the right idea for them.
Mar 27 2009









"Nick Sabalausky" <a a.a> 