www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - User defined properties signatures

reply "dvic" <dvic gmail.com> writes:
Hi guys,

It seems it's possible to define different read properties, only
differing by the return type.

Ex:

 property string value() { return m_value; } // m_value is a 
string
 property int value() { return to!int(m_value); }

But when using it in writefln() or assert for example, compiler 
(dmd) complains
about 2 different property signatures.

What I'd like to have is this:

MyObject.value = "12345"; // write property always setting a 
string

assert(MyObject.value == "12345");  // depending on the context, 
call 1st prop
assert(MyObject.value == 12345);  // depending on the context, 
call 2nd prop

Why is the compiler not complaining about defining 2 read 
properties and it does
otherwise when using both of them?

Any clue?

Thanks a lot.
Apr 20 2015
next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, April 20, 2015 18:35:34 dvic via Digitalmars-d-learn wrote:
 Hi guys,

 It seems it's possible to define different read properties, only
 differing by the return type.
Not possible. Just like pretty much any C-derived language (C++, Java, C#, etc.) the return type of a function is not considered in function overloading, and it is illegal to overload a function based on its return type.
 Why is the compiler not complaining about defining 2 read
 properties and it does
 otherwise when using both of them?
Now, that is weird. I would fully expect something like struct S { property int foo() { return 7; } property string foo() { return "foo"; } } to result in an error, but for some reason, it doesn't (and it doesn't seem to have anything to do with the fact that it's a property function). I have no idea why and would be inclined to argue that it's a compiler bug (though a compiler dev may be able to come up with a good reason for why it's acting the way it is). However, since it _is_ failing to compile as soon as you use the function, the only real problem is that if you declare a function without ever testing it, you risk having a duplicate function without knowing it. But still, I really think that the compiler should be giving an error message even if you don't call it. - Jonathan M Davis
Apr 20 2015
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 4/20/15 2:50 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Monday, April 20, 2015 18:35:34 dvic via Digitalmars-d-learn wrote:
 Why is the compiler not complaining about defining 2 read
 properties and it does
 otherwise when using both of them?
Now, that is weird. I would fully expect something like struct S { property int foo() { return 7; } property string foo() { return "foo"; } } to result in an error, but for some reason, it doesn't (and it doesn't seem to have anything to do with the fact that it's a property function).
There's an open bugzilla on this: https://issues.dlang.org/show_bug.cgi?id=2789 -Steve
Apr 20 2015
prev sibling parent reply "dvic" <dvic gmail.com> writes:
On Monday, 20 April 2015 at 18:50:31 UTC, Jonathan M Davis wrote:
 On Monday, April 20, 2015 18:35:34 dvic via Digitalmars-d-learn 
 wrote:
 Hi guys,

 It seems it's possible to define different read properties, 
 only
 differing by the return type.
Not possible. Just like pretty much any C-derived language (C++, Java, C#, etc.) the return type of a function is not considered in function overloading, and it is illegal to overload a function based on its return type.
 Why is the compiler not complaining about defining 2 read
 properties and it does
 otherwise when using both of them?
Now, that is weird. I would fully expect something like struct S { property int foo() { return 7; } property string foo() { return "foo"; } } to result in an error, but for some reason, it doesn't (and it doesn't seem to have anything to do with the fact that it's a property function). I have no idea why and would be inclined to argue that it's a compiler bug (though a compiler dev may be able to come up with a good reason for why it's acting the way it is). However, since it _is_ failing to compile as soon as you use the function, the only real problem is that if you declare a function without ever testing it, you risk having a duplicate function without knowing it. But still, I really think that the compiler should be giving an error message even if you don't call it. - Jonathan M Davis
Thanks for your answer Jonathan. But does the return type part of a method signature? I don't know what theory is claiming about that, but for me they are 2 different methods. So contextually, the best fit should prevail.
Apr 20 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, April 20, 2015 19:42:30 dvic via Digitalmars-d-learn wrote:
 Thanks for your answer Jonathan. But does the return type part of
 a method
 signature? I don't know what theory is claiming about that, but
 for me they
 are 2 different methods. So contextually, the best fit should
 prevail.
The return type is not considered in overloading. And it would complicate things considerably if it were. Some basic cases are pretty obvious, like int foo(); string foo(); int a = foo() But what about something like int foo(); float foo(); auto a = foo() + foo(); or int foo(); string foo(); void bar(int); void bar(string); bar(foo()); It's far simpler for the language to not consider return types in overloading and to simply use it for the type of the resulting expression. Then it's generally straightforward for it to determine what the type of complex expressions are. But if the return type is considered in overloading, then it gets _way_ more complicated, especially when the expressions get at all complicated. At best, the compiler would be able to work in the simple cases and error out in the complex ones, but it wouldn't take much before it would have to give up and give an error due to ambiguity. There may be languages out there which take the the return type into account when overloading, but I've never seen one. - Jonathan M Davis
Apr 20 2015
next sibling parent "dvic" <dvic gmail.com> writes:
On Monday, 20 April 2015 at 20:22:40 UTC, Jonathan M Davis wrote:
 On Monday, April 20, 2015 19:42:30 dvic via Digitalmars-d-learn 
 wrote:
 Thanks for your answer Jonathan. But does the return type part 
 of
 a method
 signature? I don't know what theory is claiming about that, but
 for me they
 are 2 different methods. So contextually, the best fit should
 prevail.
The return type is not considered in overloading. And it would complicate things considerably if it were. Some basic cases are pretty obvious, like int foo(); string foo(); int a = foo() But what about something like int foo(); float foo(); auto a = foo() + foo(); or int foo(); string foo(); void bar(int); void bar(string); bar(foo()); It's far simpler for the language to not consider return types in overloading and to simply use it for the type of the resulting expression. Then it's generally straightforward for it to determine what the type of complex expressions are. But if the return type is considered in overloading, then it gets _way_ more complicated, especially when the expressions get at all complicated. At best, the compiler would be able to work in the simple cases and error out in the complex ones, but it wouldn't take much before it would have to give up and give an error due to ambiguity. There may be languages out there which take the the return type into account when overloading, but I've never seen one. - Jonathan M Davis
Thanks Johnathan for the detailed explanation !
Apr 20 2015
prev sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Monday, 20 April 2015 at 20:22:40 UTC, Jonathan M Davis wrote:
 There may be languages out there which take the the return type 
 into account
 when overloading, but I've never seen one.
Rust does, as far as I know. I don't think that the ambiguities are an insurmountable obstacle. It's probably sufficient to error out when a call is ambiguous in its context, as can already happen during overloading. Also note that, as Ali pointed out, with multiple alias this we will be able to implement this indirectly. Which means that the compiler needs to deal with exactly the same ambiguities anyway. Might as well just take the return type into consideration directly.
Apr 21 2015
parent reply "Dicebot" <public dicebot.lv> writes:
On Tuesday, 21 April 2015 at 13:27:48 UTC, Marc Schütz wrote:
 On Monday, 20 April 2015 at 20:22:40 UTC, Jonathan M Davis 
 wrote:
 There may be languages out there which take the the return 
 type into account
 when overloading, but I've never seen one.
Rust does, as far as I know.
And this is incredibly frustrating approach that harms both readability and maintainability (you can't cut/paste RHS of an expression anymore without additional changes to the context). I have actually mentioned that when doing "first impressions" post about Rust.
Apr 21 2015
parent reply "Idan Arye" <GenericNPC gmail.com> writes:
On Tuesday, 21 April 2015 at 13:53:15 UTC, Dicebot wrote:
 On Tuesday, 21 April 2015 at 13:27:48 UTC, Marc Schütz wrote:
 On Monday, 20 April 2015 at 20:22:40 UTC, Jonathan M Davis 
 wrote:
 There may be languages out there which take the the return 
 type into account
 when overloading, but I've never seen one.
Rust does, as far as I know.
And this is incredibly frustrating approach that harms both readability and maintainability (you can't cut/paste RHS of an expression anymore without additional changes to the context). I have actually mentioned that when doing "first impressions" post about Rust.
Considering ownership and all the compile-time checks Rust does, I'd say you generally can't just cut/paste any part of an expression, or even whole statements, and expect it to just work. Also, in Rust's case this doesn't really count as overloading but as a template instantiation. BTW, the scope of this feature is much wider. Take a look at the channels example from the online book: http://doc.rust-lang.org/1.0.0-beta.2/book/concurrency.html#channels. Rust's type system is super strict, but mpsc::channel() doesn't specify the type of the stuff sent into the channel, and yet it is set correctly for both tx and rx. What's happening here is this: 1) tx.send receives an argument(or doesn't receive an argument), which lets the compiler know what the type of tx is. 2) Now that the compiler knows what the type of tx is, it knows what the type of mpsc::channel is, because it needs to match tx. 3) At this point, type inferring rx's type is straightforward. Now, Rust can do this because it has a super-strict type system. For D to be able to do this, it would have to completely reinvent it's type system, discarding many of it's idioms along the way, resulting at quite a different language.
Apr 21 2015
parent "Dicebot" <public dicebot.lv> writes:
This isn't about type system per se but about preferred style of 
syntax. Original example that caused my hatred looked like this: 
`let i : uint = from_str("42")`. Fortunately this has been 
deprecated in favor of `parse` but same principle applies - Rust 
authors encourage you to use declaration for type deduction 
instead of expression.

Same thing can be rewritten as `let i = from_str::<uint>("42")` 
without compromising any type strictness Rust is proud of. In 
this form RHS expression has clear unambiguous type and can be 
copied anywhere. But this is discouraged form. More than that, 
when I was pointing out ugly template syntax, I got some comments 
that it is OK exactly because you are always supposed to put type 
on LHS. This is purely matter of style decisions and it sucks 
hard.
Apr 21 2015
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/20/2015 11:35 AM, dvic wrote:

  property string value() { return m_value; } // m_value is a string
  property int value() { return to!int(m_value); }
Yes, as Jonathan M Davis said, that's weird.
 But when using it in writefln() or assert for example, compiler (dmd)
 complains
 about 2 different property signatures.

 What I'd like to have is this:

 MyObject.value = "12345"; // write property always setting a string

 assert(MyObject.value == "12345");  // depending on the context, call
 1st prop
 assert(MyObject.value == 12345);  // depending on the context, call 2nd
 prop
I think that would work if multiple 'alias this' were allowed. (There is a pull request that does not pass some tests; that's why it is not included in 2.067.) struct S { int int_value() { /* ... */ } string string_value() { /* ... */ } alias int_value this; alias string_value this; // ... } The matching function would be called depending on whether S is used in place of an int or a string. Ali
Apr 20 2015