digitalmars.D - possible "solution" for ufcs
- Steven Schveighoffer (37/37) Jun 06 2011 Someone wrote a very compelling argument for ufcs (uniform function call...
- Monkol (4/42) Jun 06 2011 may be you lost symbol "!" when call template opDispatch!(string name,
- KennyTM~ (2/58) Jun 06 2011 No Steven is correct. You don't need the '!' before the template paramet...
- so (5/5) Jun 06 2011 I think something is missing here.
- KennyTM~ (10/15) Jun 06 2011 auto ref opDispatch(string name, T...)(auto ref T args) {
- KennyTM~ (8/45) Jun 06 2011 Maybe better
- Timon Gehr (7/14) Jun 06 2011 Yes, but this is an unresolved problem of the language in general. We ca...
- Torarin (6/13) Jun 06 2011 As far as I understand, auto ref is supposed to mean "always ref, and
- Timon Gehr (30/67) Jun 06 2011 Great! =) This resolves everything around UFCS!
- Michel Fortin (12/22) Jun 06 2011 Clever. But how does it work for properties? Pure/safe/nothrow
- Steven Schveighoffer (33/48) Jun 06 2011 I think properties can be done, but we can't do it by marking the functi...
- Timon Gehr (4/9) Jun 06 2011 Just realized that actually it doesn't. It does not work across module
- Steven Schveighoffer (7/18) Jun 06 2011 :(
- Monkol (3/41) Jun 06 2011 what this code must to do?
- Monkol (3/41) Jun 06 2011 what this code must to do?
- Mafi (12/67) Jun 06 2011 opDispatch is special template member a class or struct can have. When
- Lutger Blijdestijn (8/60) Jun 06 2011 Nice and clever! However, I don't think it's good as an alternative for ...
- Steven Schveighoffer (29/38) Jun 06 2011 I admit I'm not warm and fuzzy on arbitrarily extending interface. For ...
- Lutger Blijdestijn (17/62) Jun 06 2011 I understand. What I find most attractive about ufcs is not really about...
- Nick Sabalausky (7/44) Jun 06 2011 --
- Nick Sabalausky (3/24) Jun 06 2011 Sorry for the partial top-posting...
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
Jun 06 2011
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? -Stevemay be you lost symbol "!" when call template opDispatch!(string name, T...)(T args)
Jun 06 2011
On Jun 7, 11 03:22, Monkol wrote:On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer <schveiguy yahoo.com> wrote:No Steven is correct. You don't need the '!' before the template parameters.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? -Stevemay be you lost symbol "!" when call template opDispatch!(string name, T...)(T args)
Jun 06 2011
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)
Jun 06 2011
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.)
Jun 06 2011
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? -SteveMaybe 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.
Jun 06 2011
KennyTM~ wrote: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.Yes, but this is an unresolved problem of the language in general. We can have the template mixin just mixin all 8 versions with different template constraints until that gets fixed (thats what will be done anyways, at least purity is reflected in the mangled name AFAIK). The most important feature needed to make it work correctly, "auto ref" is already there. Timon
Jun 06 2011
2011/6/6 KennyTM~ <kennytm gmail.com>:Maybe better =A0 =A0auto ref opDispatch(string name, T...)(auto ref T args) { =A0 =A0 =A0 =A0mixin("return ." ~ name ~ "(this, args);"); =A0 =A0} so that ref-returns and ref-parameters can be handled as well. Doesn't wo=rkfor 'lazy' though. It also cannot preserve 'pure'-ity, 'nothrow'-ness and ' safe'-ty of the original function.As far as I understand, auto ref is supposed to mean "always ref, and accept r-values". So we would need to allow tuples to contain ref types and construct it from the target function. Torarin
Jun 06 2011
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? -SteveGreat! =) 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
Jun 06 2011
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/
Jun 06 2011
On Mon, 06 Jun 2011 15:32:38 -0400, Michel Fortin <michel.fortin michelf.com> wrote:On 2011-06-06 15:00:13 -0400, "Steven Schveighoffer" <schveiguy yahoo.com> said:I think properties can be done, but we can't do it by marking the function property (which would mean something different to the compiler). Something like this might work: struct ufcs { property auto opDispatch(string s)() // TODO: appropriate constraint { mixin("return ."prop_" ~ s ~ "(this);"); } property auto opDispatch(string s, T)(T arg) // TODO: appropriate constraint { mixin("return ."prop_" ~ s ~ "(this, arg);"); } } It's very sketchy, you need to appropriately name your global functions, because naming them with property doesn't really work. Custom annotations could work well here. As far as pure/safe/nothrow, I think templates need general work in this area anyways. IFTI in particular is woefully inadequate for wrapping functions. I've proposed an enhancement to assist in this in some cases, perhaps it can be tweaked to allow all sorts of "forwarding" behavior. Essentially, I think you should be able to use another function to guide IFTI in deciding what parameter types to use. http://d.puremagic.com/issues/show_bug.cgi?id=4998And 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.Yes, but I also think if we can make UFCS optional, we give some power back to the author of the struct/class. He can choose not to participate in ufcs, and then he can control the API to his type. Plus, this can be a good interim step! It works right now! -Steve
Jun 06 2011
Steven Schveighoffer wrote:Yes, but I also think if we can make UFCS optional, we give some power back to the author of the struct/class. He can choose not to participate in ufcs, and then he can control the API to his type. Plus, this can be a good interim step! It works right now! -SteveJust realized that actually it doesn't. It does not work across module boundaries... =/ Timon
Jun 06 2011
On Mon, 06 Jun 2011 17:18:27 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:Steven Schveighoffer wrote::( Hm... this makes sense, the template is instantiated at the context level of the defining module, not the calling module. It can however work for something like std.range calling std.range or std.algorithm functions. Just not in the general sense. -SteveYes, but I also think if we can make UFCS optional, we give some power back to the author of the struct/class. He can choose not to participate in ufcs, and then he can control the API to his type. Plus, this can be a good interim step! It works right now! -SteveJust realized that actually it doesn't. It does not work across module boundaries... =/
Jun 06 2011
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? -Stevewhat this code must to do?
Jun 06 2011
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? -Stevewhat this code must to do?
Jun 06 2011
Am 06.06.2011 21:38, schrieb Monkol:On Mon, 06 Jun 2011 22:00:13 +0300, Steven Schveighoffer <schveiguy yahoo.com> wrote:opDispatch is special template member a class or struct can have. When using the dot-operator to acces members and these aren't there, opDispatch!"memmbername" is tried. Now when ou try to use uniform function call syntax (UFC) on a struct, the function-as-method you want to use is not in the struct but in the module-scope. The compiler therefore can't find any memeber and tries opDispatch which itself tries to resolve to a module-scope function using the leading dot. Through ct-string-operations and mixin the name of the function gets injected into the code. I hope I could help you. MafiSomeone 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? -Stevewhat this code must to do?
Jun 06 2011
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? -SteveNice and clever! However, I don't think it's good as an alternative for ufcs in the language, unless that is going to be dropped because of too many ambiguities. ufcs should imho be a decision on the caller side or the side of the implementor of a datatype. It should ideally be available out of the box, to be used with any type.
Jun 06 2011
On Mon, 06 Jun 2011 17:07:25 -0400, Lutger Blijdestijn <lutger.blijdestijn gmail.com> wrote:Nice and clever! However, I don't think it's good as an alternative for ufcs in the language, unless that is going to be dropped because of too many ambiguities.I admit I'm not warm and fuzzy on arbitrarily extending interface. For one, having functions in one place makes docs/members easy to look up. i.e. I can look at one file and know all the operations for a datatype, and I can look at a function call and know where to find it in the documentation. I'm a firm believer that an object's author should be in charge of the interface to his object. Hence my position on enforcing strict property syntax. However, ranges are really not in that league -- all operations on ranges are pretty much external. Only the primitives live in the type. This is something that is accepted and understood. The same thing with slices. So it's natural to want to use ufcs there. BTW, we've had several people who think capacity should be in std.array, but it is actually in core.object, this is due to the disjoint nature of slice members -- they live everywhere. This will only get worse.ufcs should imho be a decision on the caller side or the side of the implementor of a datatype. It should ideally be available out of the box, to be used with any type.I am OK with ucfs being available everywhere, but the ambiguities are difficult to work around. Especially for properties. My preference is that UFCS be supported only for builtin language types (slices, fixed-size arrays, primitives) because there is no other option for extension, and we should work on allowing author-sponsored extendability in custom types. Type wrapping in general needs a lot more support from the compiler and IFTI. The author can even explicitly only allow extendability of certain function names, with the ability to use template constraints on opDispatch. I just think it's an area we *already* need to work on, and given this solution, it naturally allows better ufcs as you can wrap functions better. -Steve
Jun 06 2011
Steven Schveighoffer wrote:On Mon, 06 Jun 2011 17:07:25 -0400, Lutger Blijdestijn <lutger.blijdestijn gmail.com> wrote:I understand. What I find most attractive about ufcs is not really about extending interfaces, but making function composition saner to read. In some libraries such as jquery and linq it's very clean to compose operations, because they work well with chaining. Although it's not the same, something similar (and actually much better) could be achieved with ranges + ufcs. Ranges want to be composed, yet I find myself often introducing temporary variables to avoid a mess of nesting. Libraries with chaining are more pleasant, imho. I'll readily believe that the problems are significant though. Another issue may be function hijacking: when I call bar.foo() where foo is my extension, and the author of bar adds a foo method to it's type, the behavior silently changes. Your proposal does give some control over that.Nice and clever! However, I don't think it's good as an alternative for ufcs in the language, unless that is going to be dropped because of too many ambiguities.I admit I'm not warm and fuzzy on arbitrarily extending interface. For one, having functions in one place makes docs/members easy to look up. i.e. I can look at one file and know all the operations for a datatype, and I can look at a function call and know where to find it in the documentation. I'm a firm believer that an object's author should be in charge of the interface to his object. Hence my position on enforcing strict property syntax.However, ranges are really not in that league -- all operations on ranges are pretty much external. Only the primitives live in the type. This is something that is accepted and understood. The same thing with slices. So it's natural to want to use ufcs there.To me, this would be a big improvement on the usability of ranges. Not saying ranges aren't usable, but this would make for much shorter and readable code.BTW, we've had several people who think capacity should be in std.array, but it is actually in core.object, this is due to the disjoint nature of slice members -- they live everywhere. This will only get worse.ufcs should imho be a decision on the caller side or the side of the implementor of a datatype. It should ideally be available out of the box, to be used with any type.I am OK with ucfs being available everywhere, but the ambiguities are difficult to work around. Especially for properties. My preference is that UFCS be supported only for builtin language types (slices, fixed-size arrays, primitives) because there is no other option for extension, and we should work on allowing author-sponsored extendability in custom types. Type wrapping in general needs a lot more support from the compiler and IFTI. The author can even explicitly only allow extendability of certain function names, with the ability to use template constraints on opDispatch. I just think it's an area we *already* need to work on, and given this solution, it naturally allows better ufcs as you can wrap functions better. -Steve
Jun 06 2011
-- ------------------------------- Not sent from an iPhone. "Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.vwn4enw5eav7ka localhost.localdomain...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?I just hope it doesn't cause real ufcs to become an even lower priority than it already is.
Jun 06 2011
"Nick Sabalausky" <a a.a> wrote in message news:isjhv6$309k$1 digitalmars.com..."Steven Schveighoffer" <schveiguy yahoo.com> wrote in message news:op.vwn4enw5eav7ka localhost.localdomain...Sorry for the partial top-posting...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 :)I just hope it doesn't cause real ufcs to become an even lower priority than it already is.
Jun 06 2011