July 03, 2013
On 07/03/2013 03:37 AM, deadalnix wrote:
> On Tuesday, 2 July 2013 at 19:47:07 UTC, Timon Gehr wrote:
>> It is an artificial limitation, because you need to add an explicit
>> check after symbol lookup to ban constructors.
>>
>
> That seems very implementation defined.

It is true for two implementations and one spec I am aware of.

> The lookup will gives you a class or struct declaration,

Hopefully the UFCS lookup gives me a fully analysed call expression.
That's the point of specifying features by rewrite rules.

> so special casing the constructor is mandatory anyway.
>

Yes, the call expression needs some kind of check in order to support struct literals. Cancelling that support in some way in case the call expression happens to have been generated by an UFCS rewrite requires another check, which complicates the formal specification of UFCS for no gain.
July 03, 2013
On Wednesday, July 03, 2013 04:54:41 Timon Gehr wrote:
> On 07/03/2013 04:12 AM, Jonathan M Davis wrote:
> > On Wednesday, July 03, 2013 04:00:45 bearophile wrote:
> >> deadalnix:
> >>> The whole point of UFCS is to be able to provide additional custom "methods" to a object (class or struct). Constructor UFCS don't fulfill that use case.
> >>> 
> >>> Nothing is removed from the language as factories method can be introduced anyway.
> >> 
> >> This frames the topic in a wrong way. Constructors are not normal functions, they are special, but functional languages show us that's it's a very good idea to see them as functions.
> >> 
> >> And the original point of UFCS doesn't matter much. What matters is what are the practical disadvantages of allowing UFCSyntax for constructors (like the original post in this thread), and what are their practical advantages/uses (like a handy usage in UFCS chains). Then we take a look at what's the resulting balance and we decide. And such decisions should then become the written specifics of this part of the D design.
> > 
> > The primary benefit of UFCS is generic code, because if uses UFCS, generic code doesn't have to care whether a function is a member function or a free function (particularly when that can vary drastically depending on what type is used to instantiate the template).
> 
> No. Generic code has to be careful with UFCS, because every method that is called on a suitable variable via UFCS can be (accidentally) replaced by the client code.

That's the whole point! If you absolutely have to be certain that it's not calling a free function, then don't use UFCS, but the primary benefits of UFCS are making it so that generic code doesn't have to care whether a function is a free function and making it so that types can overload the behavior of free functions (e.g. having a member function find which is optimized for that type and can be used in place of std.algorithm.find).

> > Construction is not and cannot be generic.
> 
> The point is that struct constructors can be generically used like other callables.
> 
> import std.stdio, std.algorithm;
> 
> struct S{
> int x;
> }
> 
> void main(){
> auto x = [1,2,3];
> writeln(x.map!S);
> }
> 
> There is nothing to be gained from subtly breaking this analogy. UFCS can be applied to any callable.
> 
> You are probably not going to like this, but the following code also works:
> 
> import std.stdio;
> 
> struct S{
> int opCall(int x){ return x+1; }
> }
> 
> S s;
> 
> void main(){
> auto x = 1;
> writeln(x.s);
> }

That is _very_ broken IMHO. It makes no sense for parens to be optional with opCall. The whole point of opCall is to overload the parens!

> > The closest that you could get would be a factory function, which is
> > quite different. But constructors themselves cannot be generic. As such,
> > using constructors with UFCS in generic code just doesn't work, meaning
> > that the only gain that you're getting from using UFCS with constructors
> > is that you get a slightly different syntax that you might like better
> > for one reason or another. But I see no technical reason why it could add
> > any benefit over simply calling the constructor normally. And as such, I
> > think that allowing UFCS to work with constructors is definitely an
> > anti-feature.
> > ...
> 
> To be an anti-feature it has to be harmful, not just of less benefit than some other (aspect of the) feature.

I _do_ think that it's harmful. It obfuscates code without adding any benefit.

- Jonathan M Davis
July 03, 2013
On 07/03/13 05:21, Jonathan M Davis wrote:
> On Wednesday, July 03, 2013 04:54:41 Timon Gehr wrote:
>> There is nothing to be gained from subtly breaking this analogy. UFCS can be applied to any callable.
>>
>> You are probably not going to like this, but the following code also works:
>>
>> import std.stdio;
>>
>> struct S{
>> int opCall(int x){ return x+1; }
>> }
>>
>> S s;
>>
>> void main(){
>> auto x = 1;
>> writeln(x.s);
>> }
> 
> That is _very_ broken IMHO. It makes no sense for parens to be optional with opCall. The whole point of opCall is to overload the parens!

This is an optional-parens issue, not an UFCS issue. Ie Timon's example
only works w/o property enforcement, what actually happens is "writeln(x.s())".
A really bad idea - yes, but it's not an UFCS and ctor specific problem.

artur
July 03, 2013
On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
> That is _very_ broken IMHO. It makes no sense for parens to be optional with
> opCall. The whole point of opCall is to overload the parens!

So much about optional parenthesis is broken. I really wish things weren't going that way, it obfusticates the difference between a callable and the result in a really nasty way, and it doesn't work for function pointers (nor does UFCS unfortunately).
July 03, 2013
On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
> On Wednesday, July 03, 2013 04:54:41 Timon Gehr wrote:
>> On 07/03/2013 04:12 AM, Jonathan M Davis wrote:
>> > On Wednesday, July 03, 2013 04:00:45 bearophile wrote:
>> >> deadalnix:
>> >>> The whole point of UFCS is to be able to provide additional
>> >>> custom "methods" to a object (class or struct). Constructor
>> >>> UFCS don't fulfill that use case.
>> >>> 
>> >>> Nothing is removed from the language as factories method can be
>> >>> introduced anyway.
>> >> 
>> >> This frames the topic in a wrong way. Constructors are not normal
>> >> functions, they are special, but functional languages show us
>> >> that's it's a very good idea to see them as functions.
>> >> 
>> >> And the original point of UFCS doesn't matter much. What matters
>> >> is what are the practical disadvantages of allowing UFCSyntax for
>> >> constructors (like the original post in this thread), and what
>> >> are their practical advantages/uses (like a handy usage in UFCS
>> >> chains). Then we take a look at what's the resulting balance and
>> >> we decide. And such decisions should then become the written
>> >> specifics of this part of the D design.
>> > 
>> > The primary benefit of UFCS is generic code, because if uses UFCS,
>> > generic code doesn't have to care whether a function is a member function
>> > or a free function (particularly when that can vary drastically depending
>> > on what type is used to instantiate the template).
>> 
>> No. Generic code has to be careful with UFCS, because every method that
>> is called on a suitable variable via UFCS can be (accidentally) replaced
>> by the client code.
>
> That's the whole point! If you absolutely have to be certain that it's not
> calling a free function, then don't use UFCS, but the primary benefits of UFCS  
> are making it so that generic code doesn't have to care whether a function is
> a free function and making it so that types can overload the behavior of free
> functions (e.g. having a member function find which is optimized for that type
> and can be used in place of std.algorithm.find).
>
>> > Construction is not and cannot be generic.
>> 
>> The point is that struct constructors can be generically used like other
>> callables.
>> 
>> import std.stdio, std.algorithm;
>> 
>> struct S{
>> int x;
>> }
>> 
>> void main(){
>> auto x = [1,2,3];
>> writeln(x.map!S);
>> }
>> 
>> There is nothing to be gained from subtly breaking this analogy. UFCS
>> can be applied to any callable.
>> 
>> You are probably not going to like this, but the following code also works:
>> 
>> import std.stdio;
>> 
>> struct S{
>> int opCall(int x){ return x+1; }
>> }
>> 
>> S s;
>> 
>> void main(){
>> auto x = 1;
>> writeln(x.s);
>> }
>
> That is _very_ broken IMHO. It makes no sense for parens to be optional with
> opCall. The whole point of opCall is to overload the parens!
>
> - Jonathan M Davis

In a UFCS chain, it would make sense for the so-called "function object":

struct Incrementor
{
    int n;
    ref int opCall(ref int i)
    {
        return i+=n;
    }
}

int i, j;
auto incrementByTwo   = Incremementor(2);
auto incrementByThree = Incremementor(3);
i.incrementByTwo;
j.incrementByThree;

Here, the "function object" is treated just like a function (it is *designed* to behave like a function), so it should benefit from the same optional parens as a normal function.

However, yeah, I think a standalone arg-less opCall with no parens is stupid (unless someone has a usecase for it?): It's an alias this in disguise, nothing more.
July 03, 2013
On 07/03/2013 04:53 PM, John Colvin wrote:
> On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
>> That is _very_ broken IMHO. It makes no sense for parens to be
>> optional with
>> opCall. The whole point of opCall is to overload the parens!
>
> So much about optional parenthesis is broken. I really wish things
> weren't going that way, it obfusticates the difference between a
> callable and the result in a really nasty way, and it doesn't work for
> function pointers (nor does UFCS unfortunately).

Yes, UFCS works.
July 03, 2013
On Wednesday, 3 July 2013 at 14:53:56 UTC, John Colvin wrote:
> On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
>> That is _very_ broken IMHO. It makes no sense for parens to be optional with
>> opCall. The whole point of opCall is to overload the parens!
>
> So much about optional parenthesis is broken. I really wish things weren't going that way, it obfusticates the difference between a callable and the result in a really nasty way, and it doesn't work for function pointers (nor does UFCS unfortunately).

While I agree with you, I think that discussion is passed. I don't think anybody wants to resurect it (IMO).
July 03, 2013
On Wednesday, 3 July 2013 at 15:05:29 UTC, Timon Gehr wrote:
> On 07/03/2013 04:53 PM, John Colvin wrote:
>> On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
>>> That is _very_ broken IMHO. It makes no sense for parens to be
>>> optional with
>>> opCall. The whole point of opCall is to overload the parens!
>>
>> So much about optional parenthesis is broken. I really wish things
>> weren't going that way, it obfusticates the difference between a
>> callable and the result in a really nasty way, and it doesn't work for
>> function pointers (nor does UFCS unfortunately).
>
> Yes, UFCS works.

struct A {}

void foo(A a) {}

void main()
{
	A a;
	auto foo_ptr = &foo;
	a.foo_ptr(); //Error: undefined identifier 'foo_ptr'
	a.foo_ptr;   //Error: no property 'foo_ptr' for type 'A'
}
July 03, 2013
On 07/03/13 17:11, John Colvin wrote:
> On Wednesday, 3 July 2013 at 15:05:29 UTC, Timon Gehr wrote:
>> On 07/03/2013 04:53 PM, John Colvin wrote:
>>> On Wednesday, 3 July 2013 at 03:22:16 UTC, Jonathan M Davis wrote:
>>>> That is _very_ broken IMHO. It makes no sense for parens to be
>>>> optional with
>>>> opCall. The whole point of opCall is to overload the parens!
>>>
>>> So much about optional parenthesis is broken. I really wish things weren't going that way, it obfusticates the difference between a callable and the result in a really nasty way, and it doesn't work for function pointers (nor does UFCS unfortunately).
>>
>> Yes, UFCS works.
> 
> struct A {}
> 
> void foo(A a) {}
> 
> void main()
> {
>     A a;
>     auto foo_ptr = &foo;
>     a.foo_ptr(); //Error: undefined identifier 'foo_ptr'
>     a.foo_ptr;   //Error: no property 'foo_ptr' for type 'A'
> }

Move the "auto foo_ptr = &foo;" line outside of `main` and it'll work.

UFCS has several problems that need to be fixed and this is just one of them, but it isn't function-pointer specific.

artur
1 2 3
Next ›   Last »