Jump to page: 1 2 3
Thread overview
UFCS and constructors
Jul 02, 2013
monarch_dodra
Jul 02, 2013
bearophile
Jul 02, 2013
Jonathan M Davis
Jul 02, 2013
deadalnix
Jul 02, 2013
Kenji Hara
Jul 02, 2013
Maxim Fomin
Jul 02, 2013
Timon Gehr
Jul 02, 2013
monarch_dodra
Jul 02, 2013
Jonathan M Davis
Jul 02, 2013
Timon Gehr
Jul 02, 2013
Maxim Fomin
Jul 02, 2013
Timon Gehr
Jul 03, 2013
deadalnix
Jul 03, 2013
bearophile
Jul 03, 2013
Jonathan M Davis
Jul 03, 2013
Timon Gehr
Jul 03, 2013
Jonathan M Davis
Jul 03, 2013
John Colvin
Jul 03, 2013
Timon Gehr
Jul 03, 2013
John Colvin
Jul 03, 2013
Artur Skawina
Jul 03, 2013
monarch_dodra
Jul 03, 2013
monarch_dodra
Jul 03, 2013
Artur Skawina
Jul 03, 2013
deadalnix
Jul 03, 2013
Timon Gehr
Jul 02, 2013
Timon Gehr
Jul 02, 2013
deadalnix
Member lookup (Was: Re: UFCS and constructors)
Jul 02, 2013
Timon Gehr
July 02, 2013
Coming back from learn here. There was an example where somebody "accidentally" called a constructor via UFCS. I am kind of surprised that it worked. I thought UFCS was for functions only, and that constructors (specifically) were off limits.

Am I mistaken? Is UFCS explicitly allowed for constructors? Or did we kind of forget to take it into account?

One of the "big" problems with allowing UFCS and constructors is that a "." which meant "scope" can now mean "function call". If I remember correctly, that is the reason why qualified calls (eg 'a'.std.uni.toLower()) aren't allowed in UFCS (Am I correct?), but with constructors, you get the same problem:

Allow me to demonstrate:

--------
import std.stdio;

struct Bar
{
    struct S
    {
        int i;
    }
    enum j = 1;
}

struct S
{
    int[10] i;
}

void main()
{
    writeln(Bar.S());   (1)
    writeln(Bar.j.S()); (2)
}
--------

(1) is a standard scope call: instantiate a Bar.S. This prints "S(0)".
(2) is actually: "get the value j from Bar, and then UFCS construct an S using that J". This prints:  "S([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])"

Furthermore, I find UFCS construction confusing on the grounds that there is no actual "constructor function" eg: "this(...)" call: This is just aggregate initialization, which looks *very* confusing when written that way.

------------------------------------

So to sum up the question: Was UFCS + constructors are really desired feature? Was it taken into account? Do we want to keep it?

In particular, the "standard" workaround of "free function constructor" (EG "Take" vs "take") would serve much better here.
July 02, 2013
monarch_dodra:

> Is UFCS explicitly allowed for constructors? Or did we kind of forget to take it into account?

I think it's allowed, but such design decisions should be written in a kind of document... instead of just in the D front end source code.

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

Bye,
bearophile
July 02, 2013
On Tuesday, July 02, 2013 09:35:38 monarch_dodra wrote:
> Coming back from learn here. There was an example where somebody "accidentally" called a constructor via UFCS. I am kind of surprised that it worked. I thought UFCS was for functions only, and that constructors (specifically) were off limits.
> 
> Am I mistaken? Is UFCS explicitly allowed for constructors? Or did we kind of forget to take it into account?

I'm not sure that it was ever decided one way or the other so much as happened into being due to how UFCS was implemented. I know that it's come up before, and folks were arguing on both sides. Personally, I think that it's a horrible idea.

- Jonathan M Davis
July 02, 2013
On Tuesday, 2 July 2013 at 07:35:39 UTC, monarch_dodra wrote:
>
> One of the "big" problems with allowing UFCS and constructors is that a "." which meant "scope" can now mean "function call".

Just for the interest - try to guess what following in D may be:

a.b = c.d();

This is a good example how overloaded D syntax is.

> --------
>
> (1) is a standard scope call: instantiate a Bar.S. This prints "S(0)".
> (2) is actually: "get the value j from Bar, and then UFCS construct an S using that J". This prints:  "S([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])"
>
> Furthermore, I find UFCS construction confusing on the grounds that there is no actual "constructor function" eg: "this(...)" call: This is just aggregate initialization, which looks *very* confusing when written that way.
>
> ------------------------------------
>
> So to sum up the question: Was UFCS + constructors are really desired feature? Was it taken into account? Do we want to keep it?

I think this worth bug issue. Even if this behavior would be proven to be correct (I guess many wish it wouldn't), bugzilla request could be posted as an ask to provide use case in D documentation site to show this behavior explicitly.

July 02, 2013
On Tuesday, 2 July 2013 at 08:16:38 UTC, Jonathan M Davis wrote:
> On Tuesday, July 02, 2013 09:35:38 monarch_dodra wrote:
>> Coming back from learn here. There was an example where somebody
>> "accidentally" called a constructor via UFCS. I am kind of
>> surprised that it worked. I thought UFCS was for functions only,
>> and that constructors (specifically) were off limits.
>> 
>> Am I mistaken? Is UFCS explicitly allowed for constructors? Or
>> did we kind of forget to take it into account?
>
> I'm not sure that it was ever decided one way or the other so much as happened
> into being due to how UFCS was implemented. I know that it's come up before,
> and folks were arguing on both sides. Personally, I think that it's a horrible
> idea.
>
> - Jonathan M Davis

We are 2. that is horrible.
July 02, 2013
On 07/02/2013 09:35 AM, monarch_dodra wrote:
>
> Furthermore, I find UFCS construction confusing on the grounds that there is no actual
> "constructor function" eg: "this(...)" call:  This is just aggregate initialization,

Aggregate initialization is the job of the constructor. It is a default constructor call.

> which looks *very* confusing when written that way.
>

I disagree, even though the example appears to be specifically designed to confuse. Actual usage looks like this:

import std.stdio, std.bigint

void main(){
    writeln(2.BigInt ^^ 123456);
}


> ------------------------------------

> So to sum up the question: Was UFCS + constructors are really desired
> feature?

UFCS allows foo(a,b) to be written as a.foo(b), if 'foo' is not a member of a.

> Was it taken into account?

I guess so.

> Do we want to keep it?
>

There is no reason to artificially ban it.

> In particular, the "standard" workaround of "free function constructor"

What is the difference?

> (EG "Take" vs "take") would serve much better here.

"take" is not a "free function constructor".
July 02, 2013
On 07/02/2013 09:35 AM, monarch_dodra wrote:
> ...
>
> One of the "big" problems with allowing UFCS and constructors is that a
> "." which meant "scope" can now mean "function call".
> ...

I missed this point.

'One of the drawbacks of UFCS is that "bar.foo" which meant "scope lookup" or "opDispatch instantiation" or "alias this lookup" can now also mean "UFCS lookup".'

Fixed.
July 02, 2013
On Tuesday, 2 July 2013 at 12:57:50 UTC, Timon Gehr wrote:
> On 07/02/2013 09:35 AM, monarch_dodra wrote:
>> ...
>>
>> One of the "big" problems with allowing UFCS and constructors is that a
>> "." which meant "scope" can now mean "function call".
>> ...
>
> I missed this point.
>
> 'One of the drawbacks of UFCS is that "bar.foo" which meant "scope lookup" or "opDispatch instantiation" or "alias this lookup" can now also mean "UFCS lookup".'
>
> Fixed.

That is an issue, we have all of this, and prioritization mechanism is implementation defined right now.
July 02, 2013
2013/7/2 deadalnix <deadalnix@gmail.com>

> On Tuesday, 2 July 2013 at 08:16:38 UTC, Jonathan M Davis wrote:
>
>> On Tuesday, July 02, 2013 09:35:38 monarch_dodra wrote:
>>
>>> Coming back from learn here. There was an example where somebody "accidentally" called a constructor via UFCS. I am kind of surprised that it worked. I thought UFCS was for functions only, and that constructors (specifically) were off limits.
>>>
>>> Am I mistaken? Is UFCS explicitly allowed for constructors? Or did we kind of forget to take it into account?
>>>
>>
>> I'm not sure that it was ever decided one way or the other so much as
>> happened
>> into being due to how UFCS was implemented. I know that it's come up
>> before,
>> and folks were arguing on both sides. Personally, I think that it's a
>> horrible
>> idea.
>>
>> - Jonathan M Davis
>>
>
> We are 2. that is horrible.
>

I don't know what design decision had been there about it.

Historically, there's no restriction against UFCS-callable entity. With 2.030 (released on May 11, 2009) and git head, following code completely works.

void foo(int[]) {}
void bar(T)(T) {}

struct Foo { int[] x; }
struct Bar { this(int[]) {} }
struct Baz { static opCall(int[]) { return 0; } }

int[] function(int[]) fp;
int[] delegate(int[]) dg;

struct Functor { int opCall(int[]) { return 0; } }
Functor fn;

void main()
{
    fp = function(int[] x){ return x; };
    dg = delegate(int[] x){ return x; };

    int[] a;
    a.foo();
    a.bar();
    auto x1 = a.Foo();
    auto x2 = a.Bar();
    auto x3 = a.Baz();
    a.fp();
    a.dg();
    a.fn();
}

While improvement of dmd front-end code, I didn't touch it. Yes, I did never designed it...

Kenji Hara


July 02, 2013
On Tuesday, 2 July 2013 at 12:46:42 UTC, Timon Gehr wrote:
> On 07/02/2013 09:35 AM, monarch_dodra wrote:
>> which looks *very* confusing when written that way.
>>
>
> I disagree, even though the example appears to be specifically designed to confuse. Actual usage looks like this:
>
> import std.stdio, std.bigint
>
> void main(){
>     writeln(2.BigInt ^^ 123456);
> }

Yeah... tailored for confusion... that could be the biggest issue actually:

I always get surprised when arrays are 1 item initialized, and even more so when done in a struct via aggregate initialization. I'd say *that* was actually the bigger culprit in my example, and the one that lead to my confusion, which I then blamed (or "called wolf") on UFCS "If it wasn't for UFCS, that would have been turned down!" UFCS actually had nothing to do with it. :(

Well, thanks for the explanation and debunk.
« First   ‹ Prev
1 2 3