www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - UFCS for struct opCall?

reply "bearophile" <bearophileHUGS lycos.com> writes:
On request by Maxim Fomin I ask an opinion here. This is a very 
small enhancement request, that for me is borderline bug report 
(so originally I didn't plan in showing it in the main D 
newsgroup):

http://d.puremagic.com/issues/show_bug.cgi?id=9857



Maybe this should be valid:


struct Foo {
     int opCall(bool b) {
         return 0;
     }
}
void main() {
    Foo foo;
    auto b1 = foo(true); // OK
    auto b2 = true.foo;  // Error
}


dmd 2.063alpha gives:

temp.d(9): Error: no property 'foo' for type 'bool'


Explanation:

1) I am using UFCS often in D, for functions, higher order 
functions, etc. A struct with an opCall method is usable like a 
function with state. So for uniformity with the other functions 
I'd like to use it with UFCS. When you have a long UFCS chain you 
don't want to break it, if it's possible.


2) Both struct constructors, struct implicit constructors and 
struct static opCall support UFCS, so I don't see a good reason 
for just the normal struct opCall to not support it:


struct Foo {
     static int opCall(int x) {
         return x * 2;
     }
}
struct Bar {
     int x;
     this(int y) {
         x = y * 2;
     }
}
struct Spam {
     int x;
}
void main() {
     assert(10.Foo == 20);
     assert(10.Bar.x == 20);
     assert(10.Spam.x == 10);
}


Jonathan Davis doesn't like this. For more information I suggest 
to take a look at the thread in Bugzilla.

- - - - - - - - - - -

Regarding UFCS, currently this doesn't work, I don't know if this 
should be considered a bug or not (I think the answer is 
positive):


struct Node {}
void foo(Node* p) {}
void main() {
     auto p = new Node();
     foo(p); // OK
     p.foo;  // Error: no property 'foo' for type 'Node'
}


Bye,
bearophile
Apr 08 2013
next sibling parent "Jesse Phillips" <Jessekphillips+d gmail.com> writes:
I see no issue with the request, I've never used a non-static 
opcall, seems odd, but for a uniform syntax I'd say go for it.

 - - - - - - - - - - -

 Regarding UFCS, currently this doesn't work, I don't know if 
 this should be considered a bug or not (I think the answer is 
 positive):


 struct Node {}
 void foo(Node* p) {}
 void main() {
     auto p = new Node();
     foo(p); // OK
     p.foo;  // Error: no property 'foo' for type 'Node'
 }


 Bye,
 bearophile
D has specified that . (dot) will dereference, I don't see this as a bug. What do you think should happen if you do have a foo(Node p) {}? Now on to Some points from the BZ entry. Jonathan, UFCS was never planned for arrays, the only reason the bug wasn't fixed was because it was nice and figured it should be expanded upon. Planning for it to only work with arrays would just be weird. Andrej, The statement related to reversing foo(a) means that you don't get a.foo(), since bearophile is requesting this it should try foo(a). Also about how long we have had UFCS: http://d.puremagic.com/issues/show_bug.cgi?id=662 This jira you reference is commented with: "UFCS for all basic types and enums is implemented in dmd 2.059." which was released in April last year. The oldest bug you mention is for the array "version."
Apr 08 2013
prev sibling next sibling parent reply kenji hara <k.hara.pg gmail.com> writes:
UFCS should just work only for 'functions'.
'foo' is not a function, rather it is a functor. So this is proper behavior.

Kenji Hara

2013/4/9 bearophile <bearophileHUGS lycos.com>

 On request by Maxim Fomin I ask an opinion here. This is a very small
 enhancement request, that for me is borderline bug report (so originally I
 didn't plan in showing it in the main D newsgroup):

 http://d.puremagic.com/issues/**show_bug.cgi?id=9857<http://d.puremagic.com/issues/show_bug.cgi?id=9857>



 Maybe this should be valid:


 struct Foo {
     int opCall(bool b) {
         return 0;
     }
 }
 void main() {
    Foo foo;
    auto b1 = foo(true); // OK
    auto b2 = true.foo;  // Error
 }


 dmd 2.063alpha gives:

 temp.d(9): Error: no property 'foo' for type 'bool'


 Explanation:

 1) I am using UFCS often in D, for functions, higher order functions, etc.
 A struct with an opCall method is usable like a function with state. So for
 uniformity with the other functions I'd like to use it with UFCS. When you
 have a long UFCS chain you don't want to break it, if it's possible.


 2) Both struct constructors, struct implicit constructors and struct
 static opCall support UFCS, so I don't see a good reason for just the
 normal struct opCall to not support it:


 struct Foo {
     static int opCall(int x) {
         return x * 2;
     }
 }
 struct Bar {
     int x;
     this(int y) {
         x = y * 2;
     }
 }
 struct Spam {
     int x;
 }
 void main() {
     assert(10.Foo == 20);
     assert(10.Bar.x == 20);
     assert(10.Spam.x == 10);
 }


 Jonathan Davis doesn't like this. For more information I suggest to take a
 look at the thread in Bugzilla.

 - - - - - - - - - - -

 Regarding UFCS, currently this doesn't work, I don't know if this should
 be considered a bug or not (I think the answer is positive):


 struct Node {}
 void foo(Node* p) {}
 void main() {
     auto p = new Node();
     foo(p); // OK
     p.foo;  // Error: no property 'foo' for type 'Node'
 }


 Bye,
 bearophile
'
Apr 08 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 05:49 AM, kenji hara wrote:
 UFCS should just work only for 'functions'.
Why? This is a superfluous complication that does not buy anything.
 'foo' is not a function, rather it is a functor. So this is proper behavior.
 ...
There is no spec, therefore calling any behaviour proper without supporting arguments is meaningless.
Apr 09 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 11:13 AM, Timon Gehr wrote:
 On 04/09/2013 05:49 AM, kenji hara wrote:
 UFCS should just work only for 'functions'.
Why? This is a superfluous complication that does not buy anything. ...
Furthermore, this rule excludes function templates from UFCS.
Apr 09 2013
parent Timothee Cour <thelastmammoth gmail.com> writes:
For sake of uniformity, UFCS should apply everywhere as a general
re-write rule, not just on functions.

a.b(args...) should first check for non-UFCS definition, then for b(a,args...):
condition.assert;
string.mixin
expression.typeof

it makes chaining easier, intermediate variables un-necessary, and
maybe even implementation easier since the rule would be general.
Apr 09 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 08 Apr 2013 23:49:14 -0400, kenji hara <k.hara.pg gmail.com> wrote:

 UFCS should just work only for 'functions'.
 'foo' is not a function, rather it is a functor. So this is proper  
 behavior.
foo.opCall is a function. When you invoke foo is synonymous with foo.opCall The same should be true for delegates, function pointers, function templates, function aliases, alias this, etc. -Steve
Apr 09 2013
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 01:48 AM, bearophile wrote:
 On request by Maxim Fomin I ask an opinion here. This is a very small
 enhancement request, that for me is borderline bug report (so originally
 I didn't plan in showing it in the main D newsgroup):

 http://d.puremagic.com/issues/show_bug.cgi?id=9857
 ...
This is getting old. We should discuss the general issue, issue 9857 is just another instance of it. Namely: If the language defines a rewrite from A to B and from B to C, is a rewrite from A to C implied? I'd say yes, because this is the obvious behaviour. If it is not there, we have to add a magical "has already been rewritten" flag, countering intuition. Furthermore, as far as I am concerned, this is easier to implement. DMD's inconsistent behaviour has been discussed on d.D.learn multiple times. Furthermore, the only argument brought up against this so far is that some language constructs are special and ergo they must be mutually incompatible. This is a complete non sequitur.
 Jonathan Davis doesn't like this. For more information I suggest to take
 a look at the thread in Bugzilla.
 ...
There is not more information there, it's just given in a blown up representation. He does not justify his opinion.
Apr 09 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 9 April 2013 at 09:03:55 UTC, Timon Gehr wrote:
 This is getting old. We should discuss the general issue, issue 
 9857 is just another instance of it.

 Namely:

 If the language defines a rewrite from A to B and from B to C, 
 is a rewrite from A to C implied?
If a + b is rewritten as a.opBinary according to operator overloading and a.opBinary as opBinary(a,..) is rewritten according to UFCS, it does not necessarily mean that this works together.
 I'd say yes, because this is the obvious behaviour. If it is 
 not there, we have to add a magical "has already been 
 rewritten" flag, countering intuition. Furthermore, as far as I 
 am concerned, this is easier to implement. DMD's inconsistent 
 behaviour has been discussed on d.D.learn multiple times.
From what I know there is no code in dmd that intentionally disables the feature and it would be harder to implement the feature than to keep things as they stand (according to discussions on bugzilla).
 Furthermore, the only argument brought up against this so far 
 is that some language constructs are special and ergo they must 
 be mutually incompatible. This is a complete non sequitur.
It seems that you ignore arguments (strictly speaking you are simplifying them).
 Jonathan Davis doesn't like this. For more information I 
 suggest to take
 a look at the thread in Bugzilla.
 ...
There is not more information there, it's just given in a blown up representation. He does not justify his opinion.
That's not funny more. It is really interesting to hear from you saying that somebody does not provide bases for opinions because it is you who are known to post argument without justification ignoring everything previous (for ex. http://www.digitalmars.com/d/archives/digitalmars/D/Possible_UDA_bug_190800.html).
Apr 09 2013
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 04:10 PM, Maxim Fomin wrote:
 On Tuesday, 9 April 2013 at 09:03:55 UTC, Timon Gehr wrote:
 This is getting old. We should discuss the general issue, issue 9857
 is just another instance of it.

 Namely:

 If the language defines a rewrite from A to B and from B to C, is a
 rewrite from A to C implied?
If a + b is rewritten as a.opBinary according to operator overloading and a.opBinary as opBinary(a,..) is rewritten according to UFCS, it does not necessarily mean that this works together.
If it does not then it has to be specified that the first a.opBinary is a different construct from the second a.opBinary.
 I'd say yes, because this is the obvious behaviour. If it is not
 there, we have to add a magical "has already been rewritten" flag,
 countering intuition. Furthermore, as far as I am concerned, this is
 easier to implement. DMD's inconsistent behaviour has been discussed
 on d.D.learn multiple times.
From what I know there is no code in dmd that intentionally disables the feature
I didn't claim it was intentional. In fact, I suspect it is an implementation bug since nothing except the implementation hints that it should not work.
 and it would be harder to implement the feature than to keep
 things as they stand (according to discussions on bugzilla).
I wouldn't know about the DMD code base.
 Furthermore, the only argument brought up against this so far is that
 some language constructs are special and ergo they must be mutually
 incompatible. This is a complete non sequitur.
It seems that you ignore arguments (strictly speaking you are simplifying them).
I am abstracting their essence. If you think there was any argument that does not fit the above description, feel free to bring it up.
 Jonathan Davis doesn't like this. For more information I suggest to take
 a look at the thread in Bugzilla.
 ...
There is not more information there, it's just given in a blown up representation. He does not justify his opinion.
That's not funny more. It is really interesting to hear from you saying that somebody does not provide bases for opinions because it is you who are known to post argument without justification ignoring everything previous (for ex. http://www.digitalmars.com/d/archives/digitalmars/D/Possible_UDA_bug_190800.html).
I am flattered you went through the hassle of searching the forums in order to build an irrelevant ad hominem argument. Note however, that the thread quoted contains justification for every opinion I have posted. On a general note, NG conversations are not linear and there may be race conditions.
Apr 09 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Tuesday, 9 April 2013 at 19:08:51 UTC, Timon Gehr wrote:
 I am abstracting their essence. If you think there was any 
 argument that does not fit the above description, feel free to 
 bring it up.
a) UFCS and overloading are distinct topics. One does not enforce other to work in a particular way. For example, UFCS does not mean that a.typeid should be rewritten as typeid(a) or foo!int can be written as int.foo. Judging by enhancement requests in bugzilla, there is trend for asking anything like 'a..b..c' to be writable as 'a.b...c' in general. None of such ideas is 100% right per se, including operator overloading. b) UFCSing operator overloading is a feature which can be easily and likely to broken. By easily broken I mean that despite the idea looks 'cool', its advantages evaporate when there are multiple opBinaries and other stuff. It is possible to rewrite conflicting function name to other and use it, but it isn't possible to rewrite conflicting basic expression in terms of other basic expressions. There is no possibility for S[my.bar.mod.opCall](). The idea blows up and you have to use function call as currently. By likely to be broken I mean higher probability to run in name conflict with operators than with regular methods (and it would happen very likely because idea seems to be popular). By the way, not all operators can be overloaded because "... These operators [comma, ternary, && and || ] were considered to create more confusion than flexibility if ever overloaded..." which does not necessarily means that this decision is "incomplete" and "non sequitur".
 Jonathan Davis doesn't like this. For more information I 
 suggest to take
 a look at the thread in Bugzilla.
 ...
There is not more information there, it's just given in a blown up representation. He does not justify his opinion.
That's not funny more. It is really interesting to hear from you saying that somebody does not provide bases for opinions because it is you who are known to post argument without justification ignoring everything previous (for ex. http://www.digitalmars.com/d/archives/digitalmars/D/Possible_UDA_bug_190800.html).
I am flattered you went through the hassle of searching the forums in order to build an irrelevant ad hominem argument. Note however, that the thread quoted contains justification for every opinion I have posted. On a general note, NG conversations are not linear and there may be race conditions.
I don't care of flattering you, but I do not like when arguments are distorted or described as being absent, or people are portrayed as having no idea what they are talking about. Surely, I do understand advantages of the idea and understand why the idea is considered to be logical, I object not because being programming sadist, but because consider idea harmful and easy to abuse.
Apr 10 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/10/2013 02:59 PM, Maxim Fomin wrote:
 On Tuesday, 9 April 2013 at 19:08:51 UTC, Timon Gehr wrote:
 I am abstracting their essence. If you think there was any argument
 that does not fit the above description, feel free to bring it up.
a) UFCS and overloading are distinct topics. One does not enforce other to work in a particular way.
But this would support my view on the matter. I think this point has not been brought up in support of your view so far.
 For example, UFCS does not mean that
 a.typeid should be rewritten as typeid(a)
This is 100% a parser feature, there is no overloading involved.
 or foo!int can be written as int.foo.
No call syntax involved.
 Judging by enhancement requests in bugzilla, there is trend for
 asking anything like 'a..b..c'  to be writable as 'a.b...c' in general.
 None of such ideas is 100% right per se, including operator overloading.
This is not precise enough for me to get anything out of it.
 b) UFCSing operator overloading is a feature which can be easily and
 likely to broken. By easily broken I mean that despite the idea looks
 'cool', its advantages evaporate when there are multiple opBinaries and
 other stuff.
This is an argument which is similar to the general scheme I have sketched. The above is a somewhat elaborate claim that operator overloading is special
 It is possible to rewrite conflicting function name to
 other and use it, but it isn't possible to rewrite conflicting basic
 expression in terms of other basic expressions.
And it is not necessary. Why would it be?
 There is no possibility for S[my.bar.mod.opCall]().
I don't get that.
 The idea blows up and you have to use function call as currently.
You have to use function calls in any case, because overloaded operators are just function templates. Whether your operation is called "+" of "f" is a mere naming issue.
 By likely to be broken I mean higher
 probability to run in name conflict with operators than with regular
 methods
Name conflicts can be resolved in the usual fashion. Name conflicts occur only if both functions accept the same kind of input. There are not many ways to meaningfully overload operators for the same kind of data type. Furthermore, the same function name is not meaningful for every function. The "more likely" rests on the assumption that infix operator names are appropriate names for more functions than other function names. This is not justified.
 (and it would happen very likely because idea seems to be popular).
This therefore assumes that "many" will furiously start to name their functions in _inappropriate_ ways. You have yet to provide a likely scenario.
 By the way, not all operators can be overloaded because "... These
 operators [comma, ternary, && and || ] were considered to create more
 confusion than flexibility if ever overloaded..."
I'd like to keep the discussion focused. We are discussing the general behaviour of rewriting, not specific rewrites. There is no question that D's treatment of non-alphanumeric function symbols is not the best possible.
 which does not necessarily means that this decision  is "incomplete" and "non
sequitur".
This sentence does not make any sense.
 ...

 [...] I do not like when arguments are
 distorted or described as being absent, or people are portrayed as
 having no idea what they are talking about.
Me neither.
 Surely, I do understand advantages of the idea and understand why the
 idea is considered to be logical,
Do you also understand why special rules that restrict orthogonality of language features are harmful?
 I object not because being programming
 sadist, but because consider idea harmful and easy to abuse.
Most D features are easy to abuse. Deciding whether a feature is used in an abusive way is subjective at best and not generally decidable by an algorithm in any case.
Apr 10 2013
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On 2013-04-10, 14:59, Maxim Fomin wrote:

 a) UFCS and overloading are distinct topics. One does not enforce othe=
r =
 to work in a particular way.
Exactly. So if a + b may be rewritten a.opBinary(b), and a.foo(b) may be= rewritten foo(a, b), it makes sense that a + b may be rewritten opBinary(a, b). Otherwise, UFCS forces operator overloading to work in a= particular way (an/or the other way around).
 For example, UFCS does not mean that a.typeid should be rewritten as  =
 typeid(a) or foo!int can be written as int.foo.
The reason UFCS does not work for the first is special casing in the parser. The reason it does not work for the second is it's not a function call at all (or, possibly, a parameter-less one).
 b) UFCSing operator overloading is a feature which can be easily and  =
 likely to broken. By easily broken I mean that despite the idea looks =
=
 'cool', its advantages evaporate when there are multiple opBinaries an=
d =
 other stuff.
[snip]
 (and it would happen very likely because idea seems to be popular).
That a feature is popular is rarely a good argument for removing it. The exact same argument has been used against operator overloading in the past, and apart from C++'s streams, I've never heard of anyone who's actually abused the feature, only these hypothetical scenarios where someone overload + to mean 'connect to database/launch missiles'. It's not a good argument. People will not start searching for ways to abuse a feature just because it's there, and accidental problems are likely to be rare and easily circumvented. Would you believe the exact same argument was used against regular function overloading back in the day?
 There is no possibility for S[my.bar.mod.opCall]().
I have no idea what you're even trying to communicate, much less prove, with this construct. Complexity is complex? People will write ugly code no matter? I guess the first part is a static opIndex, and it basically behaves like an AA with function keys and values? What are you even trying to do?
 By the way, not all operators can be overloaded because "... These  =
 operators [comma, ternary, && and || ] were considered to create more =
=
 confusion than flexibility if ever overloaded..." which does not  =
 necessarily means that this decision is "incomplete" and "non sequitur=
". Of course not. Fairly reasonable arguments are even presented right ther= e. I am still somewhat more in favor of letting the programmer have that flexibility, and berate and/or fire him/her if it ever gets used. I have occasionally wanted to overload && and ||, though in those cases | and & have been good enough. I'd love to have a few more operators, though. =C3=97 comes immediately to mind, and =E2=8B=85, =E2=88=A9, =E2=88= =AA, =E2=8A=82, and =E2=8A=83 quickly follow. -- = Simen
Apr 10 2013
prev sibling next sibling parent reply "deadalnix" <deadalnix gmail.com> writes:
On Monday, 8 April 2013 at 23:48:13 UTC, bearophile wrote:
 On request by Maxim Fomin I ask an opinion here. This is a very 
 small enhancement request, that for me is borderline bug report 
 (so originally I didn't plan in showing it in the main D 
 newsgroup):

 http://d.puremagic.com/issues/show_bug.cgi?id=9857



 Maybe this should be valid:


 struct Foo {
     int opCall(bool b) {
         return 0;
     }
 }
 void main() {
    Foo foo;
    auto b1 = foo(true); // OK
    auto b2 = true.foo;  // Error
 }


 dmd 2.063alpha gives:

 temp.d(9): Error: no property 'foo' for type 'bool'


 Explanation:

 1) I am using UFCS often in D, for functions, higher order 
 functions, etc. A struct with an opCall method is usable like a 
 function with state. So for uniformity with the other functions 
 I'd like to use it with UFCS. When you have a long UFCS chain 
 you don't want to break it, if it's possible.


 2) Both struct constructors, struct implicit constructors and 
 struct static opCall support UFCS, so I don't see a good reason 
 for just the normal struct opCall to not support it:


 struct Foo {
     static int opCall(int x) {
         return x * 2;
     }
 }
 struct Bar {
     int x;
     this(int y) {
         x = y * 2;
     }
 }
 struct Spam {
     int x;
 }
 void main() {
     assert(10.Foo == 20);
     assert(10.Bar.x == 20);
     assert(10.Spam.x == 10);
 }
I don't think this makes any sense. Constructor are not regular function. The bug lies in the fact that this work and not in the opCall not working IMO.
 Regarding UFCS, currently this doesn't work, I don't know if 
 this should be considered a bug or not (I think the answer is 
 positive):


 struct Node {}
 void foo(Node* p) {}
 void main() {
     auto p = new Node();
     foo(p); // OK
     p.foo;  // Error: no property 'foo' for type 'Node'
 }
It is unspecified if the UFCS lookup happen before or after pointer dereference, or both.
Apr 09 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 12:21 PM, deadalnix wrote:
...

 I don't think this makes any sense. Constructor are not regular
 function. The bug lies in the fact that this work and not in the opCall
 not working IMO.
 ...
On 04/09/2013 11:03 PM, Timon Gehr wrote:
 Furthermore, the only argument brought up against this so far is that some
 language constructs are special and ergo they must be mutually incompatible.
 This is a complete non sequitur.
I still do not get what this is about.
Apr 09 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/09/2013 02:40 PM, Timon Gehr wrote:
 On 04/09/2013 12:21 PM, deadalnix wrote:
 ...

 I don't think this makes any sense. Constructor are not regular
 function. The bug lies in the fact that this work and not in the opCall
 not working IMO.
 ...
On 04/09/2013 11:03 PM, Timon Gehr wrote:
That's "AM".
 Furthermore, the only argument brought up against this so far is that
 some
 language constructs are special and ergo they must be mutually
 incompatible.
 This is a complete non sequitur.
I still do not get what this is about.
Apr 09 2013
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
deadalnix:

 I don't think this makes any sense. Constructor are not regular 
 function.
From studying functional languages like Haskell I have learnt that considering "constructors" like the other functions gives some advantages. The uniformity of the idea of "function" is very useful. What you are saying here has no content, so it has no value (it's equivalent to a -0 vote). If you want to put an argument you have to explain what are the practical disadvantages/risks in D of calling a struct opCall with the UFCS. Bye, bearophile
Apr 09 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 9 April 2013 at 13:02:27 UTC, bearophile wrote:
 deadalnix:

 I don't think this makes any sense. Constructor are not 
 regular function.
From studying functional languages like Haskell I have learnt that considering "constructors" like the other functions gives some advantages. The uniformity of the idea of "function" is very useful.
Right now, in D, you'll find plenty of magic associated with constructors. This is fundamentaly problematic when you want to disguise them as functions. I would be in general for reducing the magic associated with constructor in order to allow them to behave like function, but right now, they are different beasts.
 What you are saying here has no content, so it has no value 
 (it's equivalent to a -0 vote). If you want to put an argument 
 you have to explain what are the practical disadvantages/risks 
 in D of calling a struct opCall with the UFCS.
UFCS work with function, but do not with first class functions (ie values) or delegate. opCall on struct is much closer to a delegate than a function.
Apr 09 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/9/13 10:35 AM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 13:02:27 UTC, bearophile wrote:
 deadalnix:

 I don't think this makes any sense. Constructor are not regular
 function.
From studying functional languages like Haskell I have learnt that considering "constructors" like the other functions gives some advantages. The uniformity of the idea of "function" is very useful.
Right now, in D, you'll find plenty of magic associated with constructors. This is fundamentaly problematic when you want to disguise them as functions. I would be in general for reducing the magic associated with constructor in order to allow them to behave like function, but right now, they are different beasts.
They are different than regular functions by necessity. A constructor must start on an raw object ("unprepared" in a sense) and bring it to a meaningful state. In the case of immutable and const objects, that grants the constructor special characteristics that are very unlike regular functions. So they are special. Andrei
Apr 09 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 9 April 2013 at 15:29:42 UTC, Andrei Alexandrescu 
wrote:
 They are different than regular functions by necessity. A 
 constructor must start on an raw object ("unprepared" in a 
 sense) and bring it to a meaningful state. In the case of 
 immutable and const objects, that grants the constructor 
 special characteristics that are very unlike regular functions. 
 So they are special.
They need magic inside, it doesn't need to leak outside. As now they are rvalues, this is easy to type the constructor as follow : struct S { T t; this(T t) { this.t = t; } // Becomes. static S __ctor(T t) { S this = S.init; // Magic !! this.t = t; return this; // Magic !! } } The magic don't need to leak outside.
Apr 09 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/9/13 11:43 AM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 15:29:42 UTC, Andrei Alexandrescu wrote:
 They are different than regular functions by necessity. A constructor
 must start on an raw object ("unprepared" in a sense) and bring it to
 a meaningful state. In the case of immutable and const objects, that
 grants the constructor special characteristics that are very unlike
 regular functions. So they are special.
They need magic inside, it doesn't need to leak outside.
Agreed.
 As now they are rvalues, this is easy to type the constructor as follow :

 struct S {
 T t;

 this(T t) {
 this.t = t;
 }

 // Becomes.
 static S __ctor(T t) {
 S this = S.init; // Magic !!
 this.t = t;
 return this; // Magic !!
 }
 }

 The magic don't need to leak outside.
I'm lost. Andrei
Apr 09 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 9 April 2013 at 15:56:10 UTC, Andrei Alexandrescu 
wrote:
 On 4/9/13 11:43 AM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 15:29:42 UTC, Andrei Alexandrescu 
 wrote:
 They are different than regular functions by necessity. A 
 constructor
 must start on an raw object ("unprepared" in a sense) and 
 bring it to
 a meaningful state. In the case of immutable and const 
 objects, that
 grants the constructor special characteristics that are very 
 unlike
 regular functions. So they are special.
They need magic inside, it doesn't need to leak outside.
Agreed.
 As now they are rvalues, this is easy to type the constructor 
 as follow :

 struct S {
 T t;

 this(T t) {
 this.t = t;
 }

 // Becomes.
 static S __ctor(T t) {
 S this = S.init; // Magic !!
 this.t = t;
 return this; // Magic !!
 }
 }

 The magic don't need to leak outside.
I'm lost. Andrei
What I'm saying is that no magic need to be done outside the constructor, and it can be considered as a regular function. For instance, in the code snippet above, the constructor can be translated into the __ctor function (in D like) by adding the magic. This would allow to merge constructors and functions, and handle both the same way.
Apr 09 2013
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/9/13 12:16 PM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 15:56:10 UTC, Andrei Alexandrescu wrote:
 On 4/9/13 11:43 AM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 15:29:42 UTC, Andrei Alexandrescu wrote:
 They are different than regular functions by necessity. A constructor
 must start on an raw object ("unprepared" in a sense) and bring it to
 a meaningful state. In the case of immutable and const objects, that
 grants the constructor special characteristics that are very unlike
 regular functions. So they are special.
They need magic inside, it doesn't need to leak outside.
Agreed.
 As now they are rvalues, this is easy to type the constructor as
 follow :

 struct S {
 T t;

 this(T t) {
 this.t = t;
 }

 // Becomes.
 static S __ctor(T t) {
 S this = S.init; // Magic !!
 this.t = t;
 return this; // Magic !!
 }
 }

 The magic don't need to leak outside.
I'm lost. Andrei
What I'm saying is that no magic need to be done outside the constructor, and it can be considered as a regular function. For instance, in the code snippet above, the constructor can be translated into the __ctor function (in D like) by adding the magic. This would allow to merge constructors and functions, and handle both the same way.
How do you address construction of immutable objects? Andrei
Apr 09 2013
parent reply "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 9 April 2013 at 16:22:08 UTC, Andrei Alexandrescu 
wrote:
 How do you address construction of immutable objects?
In general, the first assignement of a field in a constructor must be handled as a declaration, not as an assignement. It solve const/immutable construction issues as well as avoiding unecessary copy/destruction as Ali pointed in a recent post. The magic only happens in the constructor, so it can still be considered as a regular function seen from the outside.
Apr 09 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 4/9/13 12:27 PM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 16:22:08 UTC, Andrei Alexandrescu wrote:
 How do you address construction of immutable objects?
In general, the first assignement of a field in a constructor must be handled as a declaration, not as an assignement. It solve const/immutable construction issues as well as avoiding unecessary copy/destruction as Ali pointed in a recent post. The magic only happens in the constructor, so it can still be considered as a regular function seen from the outside.
Right. This part I agree with. All I'm saying is that constructors are typechecked differently from other functions, so they must be distinguished somehow. Probably we're in violent agreement, or if not: are you suggesting a change? Andrei
Apr 09 2013
parent "deadalnix" <deadalnix gmail.com> writes:
On Tuesday, 9 April 2013 at 16:36:09 UTC, Andrei Alexandrescu 
wrote:
 On 4/9/13 12:27 PM, deadalnix wrote:
 On Tuesday, 9 April 2013 at 16:22:08 UTC, Andrei Alexandrescu 
 wrote:
 How do you address construction of immutable objects?
In general, the first assignement of a field in a constructor must be handled as a declaration, not as an assignement. It solve const/immutable construction issues as well as avoiding unecessary copy/destruction as Ali pointed in a recent post. The magic only happens in the constructor, so it can still be considered as a regular function seen from the outside.
Right. This part I agree with. All I'm saying is that constructors are typechecked differently from other functions, so they must be distinguished somehow. Probably we're in violent agreement, or if not: are you suggesting a change?
Constructor used to create lvalues, and so behave differently. I'm not sure what is the expected behavior at the end, but I think indeed that we envision the same thing here. BTW, what do you mean by different typechecking rules ? How is it different than the code snippet posted above ?
Apr 09 2013
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/09/2013 09:27 AM, deadalnix wrote:

 In general, the first assignement of a field in a constructor must be
 handled as a declaration, not as an assignement. It solve
 const/immutable construction issues as well as avoiding unecessary
 copy/destruction as Ali pointed in a recent post.
The following thread: http://forum.dlang.org/thread/khu6tl$q8o$1 digitalmars.com It contains a link to the following enhancement request: http://d.puremagic.com/issues/show_bug.cgi?id=9732 Ali
Apr 10 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 08 Apr 2013 19:48:12 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 On request by Maxim Fomin I ask an opinion here. This is a very small  
 enhancement request, that for me is borderline bug report (so originally  
 I didn't plan in showing it in the main D newsgroup):

 http://d.puremagic.com/issues/show_bug.cgi?id=9857



 Maybe this should be valid:


 struct Foo {
      int opCall(bool b) {
          return 0;
      }
 }
 void main() {
     Foo foo;
     auto b1 = foo(true); // OK
     auto b2 = true.foo;  // Error
 }


 dmd 2.063alpha gives:

 temp.d(9): Error: no property 'foo' for type 'bool'
I agree, it should be valid. A rewrite should be a rewrite, not some special-cased thing. The rules are simple: given a.b(...) 1. if a.b(...) compiles, then call it 2. otherwise if b(a, ...) compiles, call it. 3. otherwise, error. -Steve
Apr 09 2013