| Thread overview | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
June 06, 2011 possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Someone wrote a very compelling argument for ufcs (uniform function call syntax) for ranges, and that is, given a slew of range functions, and a slew of ranges, it is nice to use a fluent programming syntax to specify wrappers for ranges without having to extend each range type. For example: take(10,stride(2,cycle([3,2,5,3]))); vs. [3,2,5,3].cycle().stride(2).take(10); And I thought damn it would be nice if ranges could implement ufcs, but other types that you didn't want to allow infinite extendability could avoid it. That gave me an idea :) import std.stdio; struct ufcs { auto opDispatch(string name, T...)(T args) // appropriate if compiles constraint here { mixin("return ." ~ name ~ "(this, args);"); } } int foo(ufcs x, int y) { writefln("it works! %d", y); return y+1; } void main() { ufcs u; auto x = u.foo(1); assert(x == 2); } And it does indeed work (2.053)... So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities. The opDispatch could even be a mixin itself (I think). What do you think? -Steve | ||||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> Someone wrote a very compelling argument for ufcs (uniform function call syntax) for ranges, and that is, given a slew of range functions, and a slew of ranges, it is nice to use a fluent programming syntax to specify wrappers for ranges without having to extend each range type. For example:
>
> take(10,stride(2,cycle([3,2,5,3])));
>
> vs.
>
> [3,2,5,3].cycle().stride(2).take(10);
>
> And I thought damn it would be nice if ranges could implement ufcs, but other types that you didn't want to allow infinite extendability could avoid it. That gave me an idea :)
>
>
> import std.stdio;
>
> struct ufcs
> {
> auto opDispatch(string name, T...)(T args) // appropriate if compiles constraint here
> {
> mixin("return ." ~ name ~ "(this, args);");
> }
> }
>
> int foo(ufcs x, int y)
> {
> writefln("it works! %d", y);
> return y+1;
> }
>
> void main()
> {
> ufcs u;
> auto x = u.foo(1);
> assert(x == 2);
> }
>
> And it does indeed work (2.053)...
>
> So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities.
>
> The opDispatch could even be a mixin itself (I think).
>
> What do you think?
>
> -Steve
may be you lost symbol "!" when call template opDispatch!(string name, T...)(T args)
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Monkol | On Jun 7, 11 03:22, Monkol wrote:
> On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer
> <schveiguy@yahoo.com> wrote:
>
>> Someone wrote a very compelling argument for ufcs (uniform function
>> call syntax) for ranges, and that is, given a slew of range functions,
>> and a slew of ranges, it is nice to use a fluent programming syntax to
>> specify wrappers for ranges without having to extend each range type.
>> For example:
>>
>> take(10,stride(2,cycle([3,2,5,3])));
>>
>> vs.
>>
>> [3,2,5,3].cycle().stride(2).take(10);
>>
>> And I thought damn it would be nice if ranges could implement ufcs,
>> but other types that you didn't want to allow infinite extendability
>> could avoid it. That gave me an idea :)
>>
>>
>> import std.stdio;
>>
>> struct ufcs
>> {
>> auto opDispatch(string name, T...)(T args) // appropriate if compiles
>> constraint here
>> {
>> mixin("return ." ~ name ~ "(this, args);");
>> }
>> }
>>
>> int foo(ufcs x, int y)
>> {
>> writefln("it works! %d", y);
>> return y+1;
>> }
>>
>> void main()
>> {
>> ufcs u;
>> auto x = u.foo(1);
>> assert(x == 2);
>> }
>>
>> And it does indeed work (2.053)...
>>
>> So we can have ufcs without any changes to the compiler, and we also
>> make it a *choice* for people who don't want to allow infinite
>> extendability, and don't want to deal with possible compiler ambiguities.
>>
>> The opDispatch could even be a mixin itself (I think).
>>
>> What do you think?
>>
>> -Steve
>
>
> may be you lost symbol "!" when call template opDispatch!(string name,
> T...)(T args)
No Steven is correct. You don't need the '!' before the template parameters.
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | I think something is missing here. It doesn't convert fun(int, ufcs) to ufcs.fun(int) as in the examples. It converts fun(ufcs, int) to ufcs.fun(int). We need is a solution to this: fun(T)(arg1, ... ufcs!T, ... argN) | |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Jun 7, 11 03:00, Steven Schveighoffer wrote:
> Someone wrote a very compelling argument for ufcs (uniform function call
> syntax) for ranges, and that is, given a slew of range functions, and a
> slew of ranges, it is nice to use a fluent programming syntax to specify
> wrappers for ranges without having to extend each range type. For example:
>
> take(10,stride(2,cycle([3,2,5,3])));
>
> vs.
>
> [3,2,5,3].cycle().stride(2).take(10);
>
> And I thought damn it would be nice if ranges could implement ufcs, but
> other types that you didn't want to allow infinite extendability could
> avoid it. That gave me an idea :)
>
>
> import std.stdio;
>
> struct ufcs
> {
> auto opDispatch(string name, T...)(T args) // appropriate if compiles
> constraint here
> {
> mixin("return ." ~ name ~ "(this, args);");
> }
> }
>
> int foo(ufcs x, int y)
> {
> writefln("it works! %d", y);
> return y+1;
> }
>
> void main()
> {
> ufcs u;
> auto x = u.foo(1);
> assert(x == 2);
> }
>
> And it does indeed work (2.053)...
>
> So we can have ufcs without any changes to the compiler, and we also
> make it a *choice* for people who don't want to allow infinite
> extendability, and don't want to deal with possible compiler ambiguities.
>
> The opDispatch could even be a mixin itself (I think).
>
> What do you think?
>
> -Steve
Maybe better
auto ref opDispatch(string name, T...)(auto ref T args) {
mixin("return ." ~ name ~ "(this, args);");
}
so that ref-returns and ref-parameters can be handled as well. Doesn't work for 'lazy' though. It also cannot preserve 'pure'-ity, 'nothrow'-ness and '@safe'-ty of the original function.
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | Steven Schveighoffer wrote:
> Someone wrote a very compelling argument for ufcs (uniform function call syntax) for ranges, and that is, given a slew of range functions, and a slew of ranges, it is nice to use a fluent programming syntax to specify wrappers for ranges without having to extend each range type. For example:
>
> take(10,stride(2,cycle([3,2,5,3])));
>
> vs.
>
> [3,2,5,3].cycle().stride(2).take(10);
>
> And I thought damn it would be nice if ranges could implement ufcs, but other types that you didn't want to allow infinite extendability could avoid it. That gave me an idea :)
>
>
> import std.stdio;
>
> struct ufcs
> {
> auto opDispatch(string name, T...)(T args) // appropriate if compiles
> constraint here
> {
> mixin("return ." ~ name ~ "(this, args);");
> }
> }
>
> int foo(ufcs x, int y)
> {
> writefln("it works! %d", y);
> return y+1;
> }
>
> void main()
> {
> ufcs u;
> auto x = u.foo(1);
> assert(x == 2);
> }
>
> And it does indeed work (2.053)...
>
> So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities.
>
> The opDispatch could even be a mixin itself (I think).
>
> What do you think?
>
> -Steve
Great! =) This resolves everything around UFCS!
Why has nobody come up with this before? You should definitely file an enhancement request for phobos.
We just add something like this somewhere:
mixin template implementUFCS() {
auto opDispatch(string name, T...)(T args) if(is(typeof({mixin("return ." ~
name ~ "(this, args);");}))){
mixin("return ." ~ name ~ "(this, args);");
}
}
Each range type will do
mixin implementUFCS;
And we'll have optional UFCS!!!
A little drawback: Types using implementUFCS will have very bad error reporting if somebody types a member name wrong:
struct foo{mixin implementUFCS;}
int main(){foo x;x.bar();}
Error: template instance opDispatch!("bar") does not match template declaration
opDispatch(string name,T...) if (is(typeof(delegate ()
{
mixin("return ." ~ name ~ "(this, args);");
}
)))
I think here a change to the compiler would be appropriate at some point so that
we can get:
Error: no property 'bar' for type 'foo'
If opDispatch does not match.
But this is definitely the way to go for UFCS!
Timon
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 2011-06-06 15:00:13 -0400, "Steven Schveighoffer" <schveiguy@yahoo.com> said: > And it does indeed work (2.053)... > > So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities. > > The opDispatch could even be a mixin itself (I think). > > What do you think? Clever. But how does it work for properties? Pure/safe/nothrow functions? Ref and out parameters? Note that properties specifically are already problem for the compiler-implemented array-member syntax. Bottom line: there's a lot of work to do to make UFCS work right. And it'll require some language-level changes anyway if we want it to work right. -- Michel Fortin michel.fortin@michelf.com http://michelf.com/ | |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> Someone wrote a very compelling argument for ufcs (uniform function call syntax) for ranges, and that is, given a slew of range functions, and a slew of ranges, it is nice to use a fluent programming syntax to specify wrappers for ranges without having to extend each range type. For example:
>
> take(10,stride(2,cycle([3,2,5,3])));
>
> vs.
>
> [3,2,5,3].cycle().stride(2).take(10);
>
> And I thought damn it would be nice if ranges could implement ufcs, but other types that you didn't want to allow infinite extendability could avoid it. That gave me an idea :)
>
>
> import std.stdio;
>
> struct ufcs
> {
> auto opDispatch(string name, T...)(T args) // appropriate if compiles constraint here
> {
> mixin("return ." ~ name ~ "(this, args);");
> }
> }
>
> int foo(ufcs x, int y)
> {
> writefln("it works! %d", y);
> return y+1;
> }
>
> void main()
> {
> ufcs u;
> auto x = u.foo(1);
> assert(x == 2);
> }
>
> And it does indeed work (2.053)...
>
> So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities.
>
> The opDispatch could even be a mixin itself (I think).
>
> What do you think?
>
> -Steve
what this code must to do?
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> Someone wrote a very compelling argument for ufcs (uniform function call syntax) for ranges, and that is, given a slew of range functions, and a slew of ranges, it is nice to use a fluent programming syntax to specify wrappers for ranges without having to extend each range type. For example:
>
> take(10,stride(2,cycle([3,2,5,3])));
>
> vs.
>
> [3,2,5,3].cycle().stride(2).take(10);
>
> And I thought damn it would be nice if ranges could implement ufcs, but other types that you didn't want to allow infinite extendability could avoid it. That gave me an idea :)
>
>
> import std.stdio;
>
> struct ufcs
> {
> auto opDispatch(string name, T...)(T args) // appropriate if compiles constraint here
> {
> mixin("return ." ~ name ~ "(this, args);");
> }
> }
>
> int foo(ufcs x, int y)
> {
> writefln("it works! %d", y);
> return y+1;
> }
>
> void main()
> {
> ufcs u;
> auto x = u.foo(1);
> assert(x == 2);
> }
>
> And it does indeed work (2.053)...
>
> So we can have ufcs without any changes to the compiler, and we also make it a *choice* for people who don't want to allow infinite extendability, and don't want to deal with possible compiler ambiguities.
>
> The opDispatch could even be a mixin itself (I think).
>
> What do you think?
>
> -Steve
what this code must to do?
| |||
June 06, 2011 Re: possible "solution" for ufcs | ||||
|---|---|---|---|---|
| ||||
Posted in reply to so | On Jun 7, 11 03:23, so wrote: > I think something is missing here. > > It doesn't convert fun(int, ufcs) to ufcs.fun(int) as in the examples. > It converts fun(ufcs, int) to ufcs.fun(int). > > We need is a solution to this: > > fun(T)(arg1, ... ufcs!T, ... argN) auto ref opDispatch(string name, T...)(auto ref T args) { mixin("alias ." ~ name ~ " f;"); alias ParameterTypeTuple!f Params; enum i = staticIndexOf!(Unqual!(typeof(this)), staticMap!(Unqual, Params)); static assert(i >= 0); return f(args[0 .. i], this, args[i .. $]); } (Doesn't work with overload set though.) | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply