Re: Is there a way to enforce UFCS?
On Friday, 6 January 2023 at 15:31:09 UTC, Salih Dincer wrote: If you don't want to get the above output you should use the previous example. But don't forget to connect alias and opCall. For example, you can use @property in version 2.0.83 without all the fanfare. I forgot one thing: if you implement getter/setter like below use inout as well. Actually, this must be a bit of a bug and neither I nor anyone else reported it! Ok they will say don't use @property. But this time the screen output will be like typeid. If you don't want that to happen, you have to use inout in getter functions. ```d struct Funy(T) { this(T x) { value = x; } T value; alias opCall this; @property: T opCall(T n) { return value = n; } T opCall() inout { return value; } } ``` SDB@79
Re: Is there a way to enforce UFCS?
On Thursday, 5 January 2023 at 23:05:17 UTC, thebluepandabear wrote: them or remove them. I agree, forbidding function call syntax would be a great usecase for `@property`. It will probably never get implemented though. In older versions, it worked when printing values with writeln. But due to an error in formattedWrite, the program breaks. So I stopped using @property. For example, you can't see the difference in: ```d struct Funy(T) { import std.conv : to; this(X)(X x) { value = x.to!T; } T value; alias value this; // [a] getter //@property T opAssign(T x) { // [b] setter return value = x; } alias opCall = opAssign; /* hack: `opAssign` methods are not used for initialization, but for subsequent assignments [c] incrementor: */ //@property T opOpAssign(string op: "+", X)(X x) { return value = value + x.to!T; } } import std.stdio; void main() { auto funy = Funy!uint(20); funy.value.writeln; // 20 funy = 10; funy.value.writeln; // 1 class Fun { Funy!int n; this(int i) { n = i; // or: n(i + 1); } } auto fun = new Fun(-2); fun.n.writeln; // -1 fun.n += 19.999; fun.n.writeln; // 18 } ``` Let's continue the fun... ```d struct Funy(T) { this(T x) { value = x; } T value; alias opCall this; //@property: T opCall(T n) { return value = n; } T opCall() { return value; } } import std.stdio; void main() { auto funy = Funy!uint(20); funy.value.writeln; // 20 funy = 10; funy.value.writeln; // 1 class Fun { Funy!int n; this(int i) { n = i; // or: n(i + 1); } } auto fun = new Fun(-2); fun.n.writeln; // -1 fun.n = 20; fun.n.writeln; // 0 } /* PRINTS: 20 10 Funy!int(-1) Funy!int(20) ``` If you don't want to get the above output you should use the previous example. But don't forget to connect alias and opCall. For example, you can use @property in version 2.0.83 without all the fanfare. SDB@79
Re: Is there a way to enforce UFCS?
them or remove them. I agree, forbidding function call syntax would be a great usecase for `@property`. It will probably never get implemented though.
Re: Is there a way to enforce UFCS?
On Thu, Jan 05, 2023 at 02:32:17PM +, Dom DiSc via Digitalmars-d-learn wrote: [...] > I think this is really another usecase for @property: we should forbid the > function call syntax for them (so one needs to use them like a variable). [...] > Properties are not functions. If you want a function, use a function. If > @properties would be the same as functions, they are superfluous garbage. > Either make something useful out of them or remove them. We have been talking about deprecating and removing @property for years now. Somebody just has to bite the bullet and push it through the deprecation process... ... OR come up with a DIP that implements @property in a sane, fully worked out way, not the half-hearted, incomplete, leaky implementation that it is today. // In my own code, I've stopped bothering with @property for the most part. Parentheses are optional for argumentless functions in general anyway, so there's really no need to write @property on anything. This works: struct S { private int _x; int x() { return _x; } } S s; int y = s.x; The only significant thing @property does right now is to add confusion when the unary & operator is used or when the property function returns a delegate. Not worth the trouble, I say. Just don't use @property at all, plain old member functions work just fine. T -- Some ideas are so stupid that only intellectuals could believe them. -- George Orwell
Re: Is there a way to enforce UFCS?
On Wednesday, 4 January 2023 at 14:21:46 UTC, bauss wrote: ```d class Foo { int bar; void setBar(Foo foo, int value) { foo.bar = value; } } void main() { foo.setBar(100); // Not UFCS - just method call to the class foo.setBar = 100; // Not UFCS - simply a setter function call (equal to the above) setBar(foo, 100); // Error } ``` I think this is really another usecase for @property: we should forbid the function call syntax for them (so one needs to use them like a variable). This is useful to enable library authors to enforce this, so that if a property is replaced by a variable (e.g. during refactoring), it's not a braking change for the users of the library. Else it could be that setters or getters are directly called, which would not compile anymore with a variable (that doesn't have getters or setters). @properties are intended to be used like variables - the only differences (and the reason why they exist) is the read or write protection they provide, and that they may be calculated on the fly (not stored in memory at all). That they are realized with a construct that looks similar to (a pair of) functions should be completely transparent for the user of a library. Properties are not functions. If you want a function, use a function. If @properties would be the same as functions, they are superfluous garbage. Either make something useful out of them or remove them.
Re: Is there a way to enforce UFCS?
On Wednesday, 4 January 2023 at 14:21:46 UTC, bauss wrote: On Wednesday, 4 January 2023 at 03:42:28 UTC, thebluepandabear wrote: ... My question is: is there a way to enforce UFCS-syntax? None of your code actually uses UFCS. This is UFCS: ``` class Foo { int bar; } void setBar(Foo foo, int value) { foo.bar = value; } void main() { foo.setBar(100); // UFCS setBar(foo, 100); // Non-UFCS (Above expands to this) } ``` This is not UFCS but just class method calling: ``` class Foo { int bar; void setBar(Foo foo, int value) { foo.bar = value; } } void main() { foo.setBar(100); // Not UFCS - just method call to the class foo.setBar = 100; // Not UFCS - simply a setter function call (equal to the above) setBar(foo, 100); // Error } ``` Also note that @property doesn't really do anything now and there's even talk about deprecating it. Althought I personally still use it, then it doesn't have much of a function and none of your code is affected if you remove it. Yeah I got mixed up. I think a good use of `@property` is for code clarity, it makes it clear which parts of your code should be treated as properties.
Re: Is there a way to enforce UFCS?
On Wednesday, 4 January 2023 at 03:42:28 UTC, thebluepandabear wrote: ... My question is: is there a way to enforce UFCS-syntax? None of your code actually uses UFCS. This is UFCS: ``` class Foo { int bar; } void setBar(Foo foo, int value) { foo.bar = value; } void main() { foo.setBar(100); // UFCS setBar(foo, 100); // Non-UFCS (Above expands to this) } ``` This is not UFCS but just class method calling: ``` class Foo { int bar; void setBar(Foo foo, int value) { foo.bar = value; } } void main() { foo.setBar(100); // Not UFCS - just method call to the class foo.setBar = 100; // Not UFCS - simply a setter function call (equal to the above) setBar(foo, 100); // Error } ``` Also note that @property doesn't really do anything now and there's even talk about deprecating it. Althought I personally still use it, then it doesn't have much of a function and none of your code is affected if you remove it.
Re: Is there a way to enforce UFCS?
On 1/3/23 19:42, thebluepandabear wrote: > @property { As your post proves, that feature is at most half-baked and is discouraged. Today, there is just one known obscure effect of using it. > void name(string name) { > _name = name; > } > d.name = "Poodle"; > In the code we can see that we have utilized UFCS (universal function > call syntax) UFCS is for calling free-standing functions as if they are member functions. Since your example already uses member functions, this feature is not UFCS. And I don't think it has a name. It is always possible to pass a single-argument with the assignment syntax: void foo(int i) {} void main() { foo = 42; } Pretty wild! :) But that's what makes your assignment above work. (Not UFCS.) > not enforced [...] we can > do the following in our code: > d.name("poodle"); I don't see a problem with that. :) > I am disappointed that `@property` does not Many people are disappointed that @property is pretty much useless. > is there a way to enforce D gives us the tools to do that but it's not trivial. The function can return an object that represents a variable (member variable or not). And an assignment to that representative object can set the actual variable. However, I tried to achieve it with an intermediary object but failed because the same ="Poodle" syntax broke it and demanded that we type the empty parenthesis. So, I think what you want does not exist. // I have a feeling something similar exists in Phobos // but I could not find it. // // This is a reference to any variable. struct MyRef(T) { T * ptr; void opAssign(T value) { *ptr = value; } void toString(scope void delegate(in char[]) sink) const { sink(*ptr); } } // This is a convenience function template so that // the users don't have to say e.g. MyRef!string // themselves. (See name() below.) auto myRef(T)(ref T var) { return MyRef!T(); } class Dog { @property name() { return myRef(_name); } private { string _name; } } void main() { Dog d = new Dog(); // Great: The following won't work. // d.name("poodle"); // However, now there is the empty parenthesis. :( d.name() = "Poodle"; import std.stdio; writeln(d.name); } Ali
Is there a way to enforce UFCS?
Say you have the following class which represents a dog : ```D class Dog { @property { string name(); void name(string name) { _name = name; } } private { string _name; } } ``` And you have the following code with constructs a `Dog` object: ```D void main() { Dog d = new Dog(); d.name = "Poodle"; writeln(d.name); } ``` In the code we can see that we have utilized UFCS (universal function call syntax) to set the properties for the object. This feature is great. We have also used D's `@property` annotation which gives us some other advantages that you can see in the documentation. The issue I have is that UFCS is not enforced, which I thought would be a rather good use for the `@property` annotation. This means that we can do the following in our code: ```D void main() { Dog d = new Dog(); d.name("poodle"); writeln(d.name()); } ``` I prefer the UFCS version over the non-UFCS version since it is more clear that it is a property and it matches closely with the official D style guide. I am disappointed that `@property` does not enforce UFCS, as I believe that it would add to its usefulness. Sometimes throughout my codebase I get confused and write properties in non-UFCS syntax, which bugs me a bit. My question is: is there a way to enforce UFCS-syntax?
Re: UFCS limit
On Friday, 17 June 2022 at 12:26:05 UTC, Antonio wrote: UFCS vs Functional curring... nice battle :-) **UFCS & CFTE** vs **Functional currying**... nice battle :-)
Re: UFCS limit
On Friday, 17 June 2022 at 01:04:28 UTC, Paul Backus wrote: On Thursday, 16 June 2022 at 23:59:06 UTC, Antonio wrote: Is it there any way to apply UFCS on the returned method in the same expression? Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions. Lets tray with a name :-) ```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } void main() { auto doHello = doSomething("Hello"); doHello("X"); "X".doHello(); } ``` Error: onlineapp.d(16): Error: no property `doHello` for type `string` It's true... the favomous "Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts." (I consider it absurd... but I'n no-one) Well lets try another possibility taking in account the power of CTFE ```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } auto doHello = doSomething("Hello"); void main() { doHello("X"); "X".doHello(); } ``` Error: onlineapp.d(3): Error: closures are not yet supported in CTFE :-/ UFCS vs Functional curring... nice battle :-)
Re: UFCS limit
On Friday, 17 June 2022 at 05:17:20 UTC, Tejas wrote: On Friday, 17 June 2022 at 01:04:28 UTC, Paul Backus wrote: Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions. Would it be worthwhile to extend the scope of UFCS to accomodate this use case as well though?? I think it would lead to a lot of confusing and ambiguity.
Re: UFCS limit
On Friday, 17 June 2022 at 05:17:20 UTC, Tejas wrote: On Friday, 17 June 2022 at 01:04:28 UTC, Paul Backus wrote: Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions. Would it be worthwhile to extend the scope of UFCS to accomodate this use case as well though?? Probably not.
Re: UFCS limit
On Friday, 17 June 2022 at 01:04:28 UTC, Paul Backus wrote: Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions. Would it be worthwhile to extend the scope of UFCS to accomodate this use case as well though??
Re: UFCS limit
On Thursday, 16 June 2022 at 23:59:06 UTC, Antonio wrote: Is it there any way to apply UFCS on the returned method in the same expression? Nope. The way UFCS works is that allows you to call free functions using member-function syntax, and member-function syntax is always `object.memberName`, so UFCS only works for functions that have a name, not anonymous functions.
UFCS limit
```d auto doSomething(string text) { return (string text2) { import std.stdio; writeln(text,",",text2); }; } void main() { doSomething("Hello")("X"); "X".doSomething("Hello")(); } ``` Compiler error: ``` ... onlineapp.d(13):expected 1 argument(s), not 2 ``` I tried with some syntax change: ```d void main() { doSomething("Hello")("X"); (doSomething("Hello"))("X"); // it works "X".(doSomething("Hello"))(); // fails!!! } ``` ```onlineapp.d(14): Error: identifier or `new` expected following `.`, not `( Is it there any way to apply UFCS on the returned method in the same expression?
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 22:11:29 UTC, user1234 wrote: On Wednesday, 1 September 2021 at 22:01:12 UTC, user1234 wrote: ``` ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } ``` user1234, Thanks! This is perfect, getting rid of the class altogether. Yes, as pointed out in your response, that class was rather useless. (For some unknown reason, I had been stuck on creating a singleton to avoid multiple gnuplot processes -- very unnecessary as I now see.). The ternary operator with the pipe id is much cleaner and leaner. Thanks again, for your time, energy and insight. Best Regards, James
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 22:01:12 UTC, user1234 wrote: On Wednesday, 1 September 2021 at 20:59:15 UTC, james.p.leblanc wrote: [...] The question is if there is a way to enable UFCS without such wrapper sorry my attention got stuck on the singleton. So my suggestion is rather to only enable the ufcs style. This highlights the fact that the class is useless, you can use a simple getter that initializes a hidden global: ```d module gnuplot_mod; import std.stdio; import std.process; import std.algorithm : each; import std.range : enumerate; ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } static void cmd(string txt) { with (gnuplot()) { stdin.writeln(txt); stdin.flush(); } } static void plot(double[] x, string txt = "ls 21 lw 2"){ with (gnuplot()) { stdin.writeln("plot '-' u 1:2 with lines ", txt); enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))(); sorry there was a format mistake not detected at compile time. ```diff - enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))(); + enumerate(x).each!(a => stdin.writefln!"%s %f"(a.index, a.value))(); ``` stdin.writeln("e"); stdin.flush(); } } void main() { double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; y.plot("ls 41 lw 8"); cmd("pause 2"); } ```
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 20:59:15 UTC, james.p.leblanc wrote: [...] The question is if there is a way to enable UFCS without such wrapper sorry my attention got stuck on the singleton. So my suggestion is rather to only enable the ufcs style. This highlights the fact that the class is useless, you can use a simple getter that initializes a hidden global: ```d module gnuplot_mod; import std.stdio; import std.process; import std.algorithm : each; import std.range : enumerate; ProcessPipes gnuplot () { __gshared ProcessPipes pipe; return pipe.pid ? pipe : (pipe = pipeProcess("/usr/local/bin/gnuplot")); } static void cmd(string txt) { with (gnuplot()) { stdin.writeln(txt); stdin.flush(); } } static void plot(double[] x, string txt = "ls 21 lw 2"){ with (gnuplot()) { stdin.writeln("plot '-' u 1:2 with lines ", txt); enumerate(x).each!((i,v) => stdin.writefln!"%s %f"(i, v))(); stdin.writeln("e"); stdin.flush(); } } void main() { double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; y.plot("ls 41 lw 8"); cmd("pause 2"); } ```
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 19:54:14 UTC, user1234 wrote: On Wednesday, 1 September 2021 at 16:02:47 UTC, james.p.leblanc wrote: Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) [...] **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** [...] Any suggestions on a better way are greatly appreciated. Best Regards, James hello, I'd suggest this: ```d shared static this() { get(); // cache instance before main(){} // to get rid of the synchronized() stmt } static Gnuplot get() { __gshared Gnuplot instance; return instance ? instance : (instance = new Gnuplot()); } ``` user1234, Thanks for your reply, I will need to look at it deeper. I also realize that my post was not so clear, to clarify: I needed to implement two wrapper functions ... that are **in** the module, but **outside** of the object, copied below: **void cmd(string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.cmd(txt);** **}** **void plot(double[] x, string txt){** **Gnuplot gp;** **gp = gp.get();** **gp.plot(x, txt);** **}** These enable use of the UFCS in main() (without prefixing with instantiated object's name **gp** ). The gp prefix only needs to be in these wrappers that exist in the module, not in the main(). The question is if there is a way to enable UFCS without such wrapper (see example in main() in original posting). Thanks again, and now I need to play a bit with your suggestion to learn from it. Best Regards, James
Re: Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
On Wednesday, 1 September 2021 at 16:02:47 UTC, james.p.leblanc wrote: Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) [...] **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** [...] Any suggestions on a better way are greatly appreciated. Best Regards, James hello, I'd suggest this: ```d shared static this() { get(); // cache instance before main(){} // to get rid of the synchronized() stmt } static Gnuplot get() { __gshared Gnuplot instance; return instance ? instance : (instance = new Gnuplot()); } ```
Singleton Object, calling member functions using UFCS (an "ugly?" example) ... better way?
Dear D-ers, For simple plotting using a gnuplot process, I have created a singleton object (a stripped down minimal working example is below.) In the example, there are two plots calls: 1) First, call is made using the object member function "gp.plot(x, etc.)" 2) The second uses a wrapper to allow use of the UFCS (uniform function call syntax) The ability to use the UFCS has the usual UFCS advantages, additionally the coder doesn't need to care about the actual name of the object's instantiation. **However, those wrapper functions in the gnuplot_mod module looks a bit silly.** **Is there a more elegant way to do this?** First, the module: -- module gnuplot_mod; import std.stdio; import std.process; import std.conv : to; class Gnuplot { // modification of wiki.dlang.org/Low-Lock_Singleton_Pattern ProcessPipes pipe; private this() { this.pipe = pipeProcess("/usr/local/bin/gnuplot") ; } private static bool instantiated_; private __gshared Gnuplot instance_; static Gnuplot get() { if (!instantiated_) { synchronized(Gnuplot.classinfo) { if (!instance_) { instance_ = new Gnuplot(); } instantiated_ = true; } } return instance_; } void cmd(string txt) { this.pipe.stdin.writeln(txt); this.pipe.stdin.flush(); return; } void plot(double[] x, string txt = "ls 21 lw 2"){ this.pipe.stdin.writeln("plot '-' u 1:2 with lines " ~ txt); foreach( ind, val ; x) this.pipe.stdin.writeln( to!string(ind) ~ " " ~ to!string(val) ); this.pipe.stdin.writeln("e"); this.pipe.stdin.flush(); } } void cmd(string txt){ Gnuplot gp; gp = gp.get(); gp.cmd(txt); } void plot(double[] x, string txt){ Gnuplot gp; gp = gp.get(); gp.plot(x, txt); } --- Now, the main ... --- import gnuplot_mod; import std.stdio; void main(){ Gnuplot gp; gp = gp.get(); double[] x = [1.1, 0.2, 3.1, 2.2, 3.1, 0.6]; double[] y = [-1.1, 0.2, -3.1, 2.2, 3.1, -0.6]; writeln("\nusing singleton's member functions: plot and cmd"); gp.plot(x, "ls 31 lw 3"); gp.cmd("pause 2"); writeln("\nusing uniform function call syntax (UFCS): plot and cmd"); y.plot("ls 41 lw 8"); cmd("pause 2"); } Any suggestions on a better way are greatly appreciated. Best Regards, James
Re: UFCS doubt
On Thursday, 8 July 2021 at 23:31:57 UTC, Antonio wrote: "It works as described in the manual, not as expected" (from MySQL haters club :-p) . Yeah, 50/285 people answering the question "What language features do you miss?" chose "UFCS for local symbols" in the [State of D survey (2018)](https://rawgit.com/wilzbach/state-of-d/master/report.html), but no one has championed a language change for it yet.
Re: UFCS doubt
On Thursday, 8 July 2021 at 22:31:49 UTC, Dennis wrote: On Thursday, 8 July 2021 at 22:24:26 UTC, Antonio wrote: I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why? UFCS does not work for nested functions. Functions declared in a local scope are not found when searching for a matching UFCS function. ... Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts. See below problematic examples. https://dlang.org/spec/function.html#pseudo-member Thanks. I read the example and the assumption of "name conflict" does not seem to be justified (from my point of view) i.e. Without dot notation, this example must fail ``` int front(int[] arr) { return arr[0]; } void main() { int[] a =[1,2,3]; auto front = 1; // front is now a variable auto y = front(a); // Error, front is not a function } ``` Changing to y = a.front() should not change the behavior (it is only a notation change )... but it does!!! ``` int front(int[] arr) { return arr[0]; } void main() { int[] a =[1,2,3]; auto front = 1; // front is now a variable auto y = a.front() // NO ERROR!!! } ``` "It works as described in the manual, not as expected" (from MySQL haters club :-p) .
Re: UFCS doubt
On Thursday, 8 July 2021 at 22:24:26 UTC, Antonio wrote: onlineapp.d(9): Error: no property `mfp` for type `onlineapp.C` I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why? https://dlang.org/spec/function.html#pseudo-member 6. Functions declared in a local scope are not found when searching for a matching UFCS function.
Re: UFCS doubt
On Thursday, 8 July 2021 at 22:24:26 UTC, Antonio wrote: I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why? UFCS does not work for nested functions. Functions declared in a local scope are not found when searching for a matching UFCS function. ... Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts. See below problematic examples. https://dlang.org/spec/function.html#pseudo-member
Re: UFCS doubt
On Thursday, 8 July 2021 at 22:24:26 UTC, Antonio wrote: I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why? UFCS only works with functions defined at top level, not nested inside other functions. That's just how it is defined i don't really know why.
UFCS doubt
In this example (extracted from https://digitalmars.com/articles/b68.html), this works: ``` class C { int a; int foo(int i) { return i + a; } } auto mfp = (C self, int i)=>self.foo(i); void main(){ auto c = new C; assert( c.mfp(20)==20); } ``` but this fails ``` class C { int a; int foo(int i) { return i + a; } } void main(){ auto mfp = (C self, int i)=>self.foo(i); auto c = new C; assert( c.mfp(20)==20); } ``` onlineapp.d(9): Error: no property `mfp` for type `onlineapp.C` I supossed that ```mfp(c,20)``` and ```c.mfp(20)``` should be equivalent because UFCS in second example, but it is not... why?
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 02:19:10 UTC, Tim wrote: On Tuesday, 26 January 2021 at 01:38:45 UTC, Q. Schroll wrote: On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Unless you have a good reason, use a slice and not a static array: double[] result; The result of std.array.array will be a slice anyway. Why would I need to use a slice instead of a static array? I'm using a static array in this instance because I have and underlying 3d vector with double[3] as its base type In that case, maybe this untested code double[3] result; res.readJson[].map!(to!double).copy(result[]);
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 01:38:45 UTC, Q. Schroll wrote: On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Unless you have a good reason, use a slice and not a static array: double[] result; The result of std.array.array will be a slice anyway. Why would I need to use a slice instead of a static array? I'm using a static array in this instance because I have and underlying 3d vector with double[3] as its base type
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Unless you have a good reason, use a slice and not a static array: double[] result; The result of std.array.array will be a slice anyway.
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Json json = res.readJson; for(int i = 0; i < json.length; i++){ result[i] = json[i].to!double; } I'd prefer to do something like: result = res.readJson[].map!(to!double); Use std.array.array (alias: std.range.array) to make the range returned my map!(to!double) into an array. Note that the result of map isn't actually evaluated until it is iterated. std.array.array will iterate and collect. https://dlang.org/phobos/std_array.html#array result = res.readJson[].map!(to!double).array; should work perfectly.
How can I use UFCS for a loop
Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Json json = res.readJson; for(int i = 0; i < json.length; i++){ result[i] = json[i].to!double; } I'd prefer to do something like: result = res.readJson[].map!(to!double);
Re: UFCS functions with both pointers and refs
Two differents types; Foo type and pointer type. Need function overload foe each or just use ref and avoid pointer.
Re: UFCS functions with both pointers and refs
On Tuesday, 15 December 2020 at 20:38:04 UTC, Dave P. wrote: The use case would be to define extension methods on a struct outside of where the struct is defined. The extension method mutates the state of the struct, so I want to ensure I am modifying the original struct and not a copy. If it’s a method and I call it on a pointer to the struct, the pointer will get auto-dereferenced and everything is great. So my question is that if I want an extension method as a free function, do I have to write both the version whose first argument is a pointer to the struct and the version whose first argument is a ref, or is there some keyword or other technique so that the pointer gets auto-dereferenced the same way as if it were a method. It sounds like the answer is no and I have to write a version that just dereferences the pointer and calls the ref version. Now it's coming together. The easiest way to do this is using an overload taking a `ref` (non-pointer) value and another taking a pointer (by copy, I guess). R f(ref T value, Ts args) { /* doing the actual work */ } R f(T* ptr, Ts args) { f(*p, args); } // manually dereference You cannot get around doing the actual `f`, and the addition isn't that big. I think that's the best solution unless you have to deal with non-copyable types among Ts. Then you need to forward those properly. I couldn't really do better using one template instead of this simple overload. (Certainly a template can be made, but it is clearly not the better solution.)
Re: UFCS functions with both pointers and refs
On Wednesday, 16 December 2020 at 03:50:07 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote: On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: [...] Based on you requirement to use pointers, I assume you're doing this for a type you get from a C library. I did the same thing for the SDL_Rect type when working with SDL. All I did was implement a pointer version of my "extension" functions. When I had an instance and not a pointer, I took its address when I called the function. If that's inconvenient (lots of generic code, perhaps), you can always have the pointer version forward to the ref version, but it seems to me like just having the one version is the way to go most of the time. Yeah, in this case the C library is the rest of my program :). I am porting an application I had written in C to D in betterC mode piece by piece and there’s a good number of functions where it’d be convenient to call them via UFCs. Thanks for answering my questions!
Re: UFCS functions with both pointers and refs
On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote: On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes. Is there any way to write the function as a template that is generic over a parameter being a pointer or a reference, but does not allow passing a copy? Even with a templated function, you'd still need to declare the first parameter to the function either as a pointer or as a `ref` parameter. I'm unaware of any way to get around that. Free functions and member functions are just different beasts Based on you requirement to use pointers, I assume you're doing this for a type you get from a C library. I did the same thing for the SDL_Rect type when working with SDL. All I did was implement a pointer version of my "extension" functions. When I had an instance and not a pointer, I took its address when I called the function. If that's inconvenient (lots of generic code, perhaps), you can always have the pointer version forward to the ref version, but it seems to me like just having the one version is the way to go most of the time.
Re: UFCS functions with both pointers and refs
On Tuesday, 15 December 2020 at 19:45:50 UTC, Q. Schroll wrote: On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote: On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes. Is there any way to write the function as a template that is generic over a parameter being a pointer or a reference, but does not allow passing a copy? I'm not sure what you mean by a reference. D doesn't have references in general, only class references that are just glorified pointers. There are also `ref` parameters, but those aren't generally referred to as "references" and are inside the function almost indiscernible from non-ref parameters. So, I'll ignore that. Copying only takes place under one circumstance: When an lvalue is passed to a function that does not take that argument by `ref`. So one possibility is to just define that overload and @disable it. You don't even need a template for this: void f(X x); // matches lvalues and rvalues void f(ref X x); // matches lvalues only The latter is a better match than the former for lvalues. @disable'ing it will do the job. On the other hand, not @disable'ing it will make `f` work with any argument by moving rvalues to the former overload and referencing lvalues using the second one. On templates, those can be unified by slapping `auto ref` before the parameter. You can also use `auto ref` (which infers `ref` from the passed argument) and check it with an `if` template constraint: void f(T)(auto ref T arg) if (!__tratis(isRef, arg)) // only accepts non-ref args { /* your code here */ } The constraint can easily be flipped. The use case would be to define extension methods on a struct outside of where the struct is defined. The extension method mutates the state of the struct, so I want to ensure I am modifying the original struct and not a copy. If it’s a method and I call it on a pointer to the struct, the pointer will get auto-dereferenced and everything is great. So my question is that if I want an extension method as a free function, do I have to write both the version whose first argument is a pointer to the struct and the version whose first argument is a ref, or is there some keyword or other technique so that the pointer gets auto-dereferenced the same way as if it were a method. It sounds like the answer is no and I have to write a version that just dereferences the pointer and calls the ref version. Thanks for the explanation though!
Re: UFCS functions with both pointers and refs
On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote: On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes. Is there any way to write the function as a template that is generic over a parameter being a pointer or a reference, but does not allow passing a copy? I'm not sure what you mean by a reference. D doesn't have references in general, only class references that are just glorified pointers. There are also `ref` parameters, but those aren't generally referred to as "references" and are inside the function almost indiscernible from non-ref parameters. So, I'll ignore that. Copying only takes place under one circumstance: When an lvalue is passed to a function that does not take that argument by `ref`. So one possibility is to just define that overload and @disable it. You don't even need a template for this: void f(X x); // matches lvalues and rvalues void f(ref X x); // matches lvalues only The latter is a better match than the former for lvalues. @disable'ing it will do the job. On the other hand, not @disable'ing it will make `f` work with any argument by moving rvalues to the former overload and referencing lvalues using the second one. On templates, those can be unified by slapping `auto ref` before the parameter. You can also use `auto ref` (which infers `ref` from the passed argument) and check it with an `if` template constraint: void f(T)(auto ref T arg) if (!__tratis(isRef, arg)) // only accepts non-ref args { /* your code here */ } The constraint can easily be flipped.
Re: UFCS functions with both pointers and refs
On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes. Is there any way to write the function as a template that is generic over a parameter being a pointer or a reference, but does not allow passing a copy?
Re: UFCS functions with both pointers and refs
On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: If I define a method on a type, then I can call it both through a pointer and through a reference and the compiler does the right thing. Eg: struct Foo { int x; void fooey(){ x++; } void report(){ printf("%d\n", x); } } int main(){ Foo f; f.fooey; Foo* pf = pf.fooey; f.report; // prints 2 return 0; } However, if I define it as a free function and try to invoke it via UFCS, it seems like I have to define it twice. struct Foo { int x; void report(){ printf("%d\n", x); } } void fooey(Foo* f){ f.x++; } void fooey(ref Foo f){ f.x++; } int main(){ Foo f; f.fooey; Foo* pf = pf.fooey; f.report; // prints 2 return 0; } Am I missing something or is this just how it has to work generally? These are two very different concepts. Member functions have a hidden 'this' parameter as the first function parameter. For structs, it's a reference to the instance. Whether you call it through a pointer or a reference, that never changes: there's only one implementation of the function, the first parameter is always a reference to the instance. Free functions do not belong to any type (hence the "free"). UFCS doesn't change that. UFCS is simply a convenience that rewrites `foo.func` as `func(foo)`. You aren't calling "through" a pointer or a reference. So if the first parameter is a pointer, you can't give it a reference, and vice versa. Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes.
UFCS functions with both pointers and refs
If I define a method on a type, then I can call it both through a pointer and through a reference and the compiler does the right thing. Eg: struct Foo { int x; void fooey(){ x++; } void report(){ printf("%d\n", x); } } int main(){ Foo f; f.fooey; Foo* pf = pf.fooey; f.report; // prints 2 return 0; } However, if I define it as a free function and try to invoke it via UFCS, it seems like I have to define it twice. struct Foo { int x; void report(){ printf("%d\n", x); } } void fooey(Foo* f){ f.x++; } void fooey(ref Foo f){ f.x++; } int main(){ Foo f; f.fooey; Foo* pf = pf.fooey; f.report; // prints 2 return 0; } Am I missing something or is this just how it has to work generally? Do I have to write both and have one forward to the other for more complicated functions?
Re: How Performance down slow it is using UFCS friendly function?
On Saturday, 21 November 2020 at 00:26:03 UTC, Marcone wrote: // Função receive() char[] receive(Socket socket, int size = 8192) nothrow { try { char[] buffer; buffer.length = size; int rq = socket.receive(buffer); return buffer[0..rq]; } catch(Throwable){return null;} } s = new Socket(AddressFamily.INET, SocketType.STREAM); writeln(s.receive(8192)); // How slow is using as friendly function? Calling a function with or without UFCS makes absolutely no difference to performance. The compiler will generate the exact same code whether you write `receive(s, 8192)` or `s.receive(8192)`.
How Performance down slow it is using UFCS friendly function?
// Função receive() char[] receive(Socket socket, int size = 8192) nothrow { try { char[] buffer; buffer.length = size; int rq = socket.receive(buffer); return buffer[0..rq]; } catch(Throwable){return null;} } s = new Socket(AddressFamily.INET, SocketType.STREAM); writeln(s.receive(8192)); // How slow is using as friendly function?
Function Templates with Only Template Parameters and UFCS
Given the code: ``` auto foo(alias A, string str)() { // do stuff } struct Bar { // members } Bar bar; bar.foo!"hello"; // This is an error. Would have to do foo!(bar, "hello") ``` Assuming that I haven't misunderstood or borked something, having UFCS for function templates whose parameters are only for the template would, seemingly, be nice. Are there workarounds? Is it possible to implement, and possibly the more important question, is it a good idea? One downside is there would be more ambiguity when one is parsing that last line.
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 12:23:11 UTC, Simen Kjærås wrote: Of course, nothing stops us from defining our own front, popFront and friends that combine the two approaches above: [...] We could conceivably add these to std.range.primitives (probably adding some constraints first), and suddenly UFCS ranges are possible! (I am as of yet not convinced that we should, though) -- Simen This is basically what C++ calls "argument-dependent lookup." Discussion about adding this sort of thing to D has come up before on the forums [1], and iirc Walter has generally been opposed to it. If it were to be added as a library feature, it would probably have to be opt-in. [1] https://forum.dlang.org/post/mailman.123.1472818535.2965.digitalmar...@puremagic.com
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 09:16:58 UTC, user1234 wrote: The static checker doesn't see your free funcs because to do so it would have to import the whole module. (is it possible to do that ? no idea.) Of course it's possible! :) We can find the context of R (in this case, the module) with __traits(parent), and import that: mixin("import "~__traits(parent, R).stringof["module ".length..$]~";"); However, doing that in isInputRange doesn't help much. First, all other range functions would have to do it, and second, just importing into function scope doesn't enable UFCS lookup. Also your signature for the primitives are quite unusual (i.e not idiomatic). Usually they dont take param. Usually we pass a type that contains the member funcs matching to IsIntputRange. You can see a good counterexample to this in https://dlang.org/library/std/range/primitives/pop_front.html, which defines popFront for regular arrays. However, that is the one and only counterexample I know of. Of course, nothing stops us from defining our own front, popFront and friends that combine the two approaches above: template front(R) { auto front(R r) { return __traits(getMember, __traits(parent, R), "front")(r); } } template popFront(R) { auto popFront(R r) { return __traits(getMember, __traits(parent, R), "popFront")(r); } } template empty(R) { auto empty(R r) { return __traits(getMember, __traits(parent, R), "empty")(r); } } We could conceivably add these to std.range.primitives (probably adding some constraints first), and suddenly UFCS ranges are possible! (I am as of yet not convinced that we should, though) -- Simen
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote: struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { import std.range.primitives : isInputRange; static assert(isInputRange!R); } Error: static assert: `isInputRange!(R)` is false Whats really weird is that if I replace isInputRange with its definition from std.range.primitives, it returns true: import std; struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { static assert(is(typeof(R.init) == R) && is(ReturnType!((R r) => r.empty) == bool) && is(typeof((return ref R r) => r.front)) && !is(ReturnType!((R r) => r.front) == void) && is(typeof((R r) => r.popFront))); } This compiles. What’s going on here? The static checker doesn't see your free funcs because to do so it would have to import the whole module. (is it possible to do that ? no idea.) Also your signature for the primitives are quite unusual (i.e not idiomatic). Usually they dont take param. Usually we pass a type that contains the member funcs matching to IsIntputRange.
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote: struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { import std.range.primitives : isInputRange; static assert(isInputRange!R); } Error: static assert: `isInputRange!(R)` is false What’s going on here? The template IsInputRange is in the std.range.primitives module, and thus can't see the front, popFront and empty definitions in your module. -- Simen
Can’t use UFCS to create InputRange?
struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { import std.range.primitives : isInputRange; static assert(isInputRange!R); } Error: static assert: `isInputRange!(R)` is false Whats really weird is that if I replace isInputRange with its definition from std.range.primitives, it returns true: import std; struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { static assert(is(typeof(R.init) == R) && is(ReturnType!((R r) => r.empty) == bool) && is(typeof((return ref R r) => r.front)) && !is(ReturnType!((R r) => r.front) == void) && is(typeof((R r) => r.popFront))); } This compiles. What’s going on here?
Re: No UFCS with nested functions?
On Tuesday, November 5, 2019 9:16:27 AM MST ixid via Digitalmars-d-learn wrote: > On Monday, 4 November 2019 at 20:46:41 UTC, H. S. Teoh wrote: > > On Mon, Nov 04, 2019 at 07:51:26PM +, Tobias Pankrath via > > > > Digitalmars-d-learn wrote: > >> Why does the following not work? It works, if I move the > >> 'prop' out of 'foo'. > > > > UFCS is only supported for module-level functions, as far as I > > know. > > > >> --- > >> struct S { > >> > >>ubyte[12] bar; > >> > >> } > >> > >> bool foo (ref S s) > >> { > >> > >>static bool prop(const(ubyte)[] f) { > >> > >> return f.length > 1; > >> > >>} > >> > >>return s.bar[].prop; > >> > >> } > >> --- > > > > [...] > > > > > > T > > Is this a necessary limitation? It feels inconsistent and clunky. It's explained at the end of this section of the documentation: https://dlang.org/spec/function.html#pseudo-member - Jonathan M Davis
Re: No UFCS with nested functions?
On Monday, 4 November 2019 at 20:46:41 UTC, H. S. Teoh wrote: On Mon, Nov 04, 2019 at 07:51:26PM +, Tobias Pankrath via Digitalmars-d-learn wrote: Why does the following not work? It works, if I move the 'prop' out of 'foo'. UFCS is only supported for module-level functions, as far as I know. --- struct S { ubyte[12] bar; } bool foo (ref S s) { static bool prop(const(ubyte)[] f) { return f.length > 1; } return s.bar[].prop; } --- [...] T Is this a necessary limitation? It feels inconsistent and clunky.
Re: No UFCS with nested functions?
On Tuesday, 5 November 2019 at 00:34:33 UTC, Nicholas Wilson wrote: https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ struct S { ubyte[12] bar; } alias I(alias f) = f; bool foo (ref S s) { static bool prop(const(ubyte)[] f) { return f.length > 1; } return s.bar[].I!prop; } It's in Phobos: import std.meta: Alias; return s.bar[].Alias!prop
Re: No UFCS with nested functions?
On Monday, 4 November 2019 at 19:51:26 UTC, Tobias Pankrath wrote: Why does the following not work? It works, if I move the 'prop' out of 'foo'. --- struct S { ubyte[12] bar; } bool foo (ref S s) { static bool prop(const(ubyte)[] f) { return f.length > 1; } return s.bar[].prop; } --- Thanks! https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ struct S { ubyte[12] bar; } alias I(alias f) = f; bool foo (ref S s) { static bool prop(const(ubyte)[] f) { return f.length > 1; } return s.bar[].I!prop; }
Re: No UFCS with nested functions?
On Mon, Nov 04, 2019 at 07:51:26PM +, Tobias Pankrath via Digitalmars-d-learn wrote: > Why does the following not work? It works, if I move the 'prop' out of > 'foo'. UFCS is only supported for module-level functions, as far as I know. > --- > struct S { > ubyte[12] bar; > } > > bool foo (ref S s) > { >static bool prop(const(ubyte)[] f) { > return f.length > 1; >} > return s.bar[].prop; > } > --- [...] T -- I am not young enough to know everything. -- Oscar Wilde
No UFCS with nested functions?
Why does the following not work? It works, if I move the 'prop' out of 'foo'. --- struct S { ubyte[12] bar; } bool foo (ref S s) { static bool prop(const(ubyte)[] f) { return f.length > 1; } return s.bar[].prop; } --- Thanks!
Re: Cannot use UFCS in lambda?
On Sunday, 16 September 2018 at 10:55:43 UTC, berni wrote: The problem is more general: you can only use top-level symbols in UFCS. You can use an identity alias template to bypass this: https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ (search for UFCS in the page). Good to know. :-) Worth noting, this is now included in Phobos as `std.meta.Alias`.
Re: Cannot use UFCS in lambda?
The problem is more general: you can only use top-level symbols in UFCS. You can use an identity alias template to bypass this: https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ (search for UFCS in the page). Good to know. :-)
Re: Cannot use UFCS in lambda?
On Sunday, 16 September 2018 at 09:46:15 UTC, berni wrote: Where is my mistake? Lambdas are not the issue here. The problem is more general: you can only use top-level symbols in UFCS. You can use an identity alias template to bypass this: https://blog.thecybershadow.net/2015/04/28/the-amazing-template-that-does-nothing/ (search for UFCS in the page).
Cannot use UFCS in lambda?
The following program does not compile: import std.stdio; import std.algorithm; struct A { struct S { int x; } const bool foo(in S s, in int k) { return s.xa.foo(3)).writeln; } } void main() { A().bar(); } I get (using rdmd): test.d(18): Error: no property foo for type S /usr/include/dmd/phobos/std/algorithm/iteration.d(1108): instantiated from here: >FilterResult!(__lambda1, S[]) test.d(18):instantiated from here: filter!(S[]) When I replace the UFCS-Syntax in the lambda by a function call it works: [S(1),S(2),S(3),S(4),S(5)].filter!(a=>foo(a,3)).writeln; Where is my mistake?
Re: Why does not UFCS work for method defined inside unittest block?
On Tuesday, 31 July 2018 at 08:42:28 UTC, Simen Kjærås wrote: From https://dlang.org/spec/function.html#pseudo-member: "A free function can be called with a syntax that looks as if the function were a member function of its first parameter type." [...] Thanks a lot Simen :)
Re: Why does not UFCS work for method defined inside unittest block?
On Tuesday, 31 July 2018 at 08:28:01 UTC, Ky-Anh Huynh wrote: Hi, Can I define a new quick function to use inside a unittest block? I have the following code: [code] auto foo(string[] sta) { return sta; } auto bar(string[] sta) { return sta; } auto h(string[] sta) { return sta.foo.bar; } unittest { import std.format; auto f = (string[] sta) => sta.foo.bar; auto g(string[] sta) { return sta.foo.bar; } assert(f(["test"]) == ["test"]); assert(g(["test"]) == ["test"]); assert(["test"].h == ["test"]); assert(["test"].g == ["test"]); } [/code] (Src: https://gist.github.com/icy/64ec1838929d448d9f874d1e8261e56a) The last test will fail: Error: no property g for type string[] Please advise. From https://dlang.org/spec/function.html#pseudo-member: "A free function can be called with a syntax that looks as if the function were a member function of its first parameter type." A function defined in a function scope (which a unittest block is), is not a free function, and so does not benefit from UFCS. There is an explanation for why at the bottom of the above page: "The reason why local symbols are not considered by UFCS, is to avoid unexpected name conflicts." If you need a function that's available for UFCS in a unittest but is not there in a non-unittest context, use a version block: version (unittest) { auto fun(string[] s) { return s } } And if you need something with a context: version (unittest) { string delegate (string) test; } unittest { string s1 = "foo"; test = s => s ~ s1; "foo".test; } -- Simen
Re: Why does not UFCS work for method defined inside unittest block?
dmd version that I'm using: $ dmd --version DMD64 D Compiler v2.081.1-dirty Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved written by Walter Bright
Why does not UFCS work for method defined inside unittest block?
Hi, Can I define a new quick function to use inside a unittest block? I have the following code: [code] auto foo(string[] sta) { return sta; } auto bar(string[] sta) { return sta; } auto h(string[] sta) { return sta.foo.bar; } unittest { import std.format; auto f = (string[] sta) => sta.foo.bar; auto g(string[] sta) { return sta.foo.bar; } assert(f(["test"]) == ["test"]); assert(g(["test"]) == ["test"]); assert(["test"].h == ["test"]); assert(["test"].g == ["test"]); } [/code] (Src: https://gist.github.com/icy/64ec1838929d448d9f874d1e8261e56a) The last test will fail: Error: no property g for type string[] Please advise. Thanks a lot.
Re: UFCS confusion
On Friday, 13 July 2018 at 11:37:09 UTC, Michael wrote: On Friday, 13 July 2018 at 11:17:32 UTC, Radu wrote: On Friday, 13 July 2018 at 11:12:47 UTC, Michael wrote: On Friday, 13 July 2018 at 10:52:54 UTC, Radu wrote: On Friday, 13 July 2018 at 10:21:54 UTC, Michael wrote: [...] Do you try to call member functions? UFCS only works with free functions, meaning declared at module level. https://dlang.org/spec/function.html#pseudo-member I'm not intentionally trying to call member functions, no. The functions are all static functions of a class, but the chaining of them using UFCS doesn't seem to work. OK, static functions of a class are static *member* functions, they are not free functions. Oh, really? Well that will explain it then. I was sure I had used this syntax before but perhaps not. Thanks for your help! try this: import std.functional : pipe; createVector(langSize, index).pipe!createSet.length;
Re: UFCS confusion
On Friday, 13 July 2018 at 11:17:32 UTC, Radu wrote: On Friday, 13 July 2018 at 11:12:47 UTC, Michael wrote: On Friday, 13 July 2018 at 10:52:54 UTC, Radu wrote: On Friday, 13 July 2018 at 10:21:54 UTC, Michael wrote: [...] Do you try to call member functions? UFCS only works with free functions, meaning declared at module level. https://dlang.org/spec/function.html#pseudo-member I'm not intentionally trying to call member functions, no. The functions are all static functions of a class, but the chaining of them using UFCS doesn't seem to work. OK, static functions of a class are static *member* functions, they are not free functions. Oh, really? Well that will explain it then. I was sure I had used this syntax before but perhaps not. Thanks for your help!
Re: UFCS confusion
On Friday, 13 July 2018 at 11:12:47 UTC, Michael wrote: On Friday, 13 July 2018 at 10:52:54 UTC, Radu wrote: On Friday, 13 July 2018 at 10:21:54 UTC, Michael wrote: [...] Do you try to call member functions? UFCS only works with free functions, meaning declared at module level. https://dlang.org/spec/function.html#pseudo-member I'm not intentionally trying to call member functions, no. The functions are all static functions of a class, but the chaining of them using UFCS doesn't seem to work. OK, static functions of a class are static *member* functions, they are not free functions.
Re: UFCS confusion
On Friday, 13 July 2018 at 10:52:54 UTC, Radu wrote: On Friday, 13 July 2018 at 10:21:54 UTC, Michael wrote: Hello, I am nesting some function calls, and I'm pretty used to making use of D's Uniform Function Call Syntax, but I'm getting an error if I try to convert this line: createSet(createVector(langSize, index)).length; which works, into this line: createVector(langSize, index).createSet.length; receiving the error "Error: no property createSet for type int[]", when the signature for createSet is: static auto createSet(in int[] vector) pure What am I missing here? I'm sure it's stupidly obvious but it expects one argument, so I'm just calling it without parentheses. Do you try to call member functions? UFCS only works with free functions, meaning declared at module level. https://dlang.org/spec/function.html#pseudo-member I'm not intentionally trying to call member functions, no. The functions are all static functions of a class, but the chaining of them using UFCS doesn't seem to work.
Re: UFCS confusion
On Friday, 13 July 2018 at 10:21:54 UTC, Michael wrote: Hello, I am nesting some function calls, and I'm pretty used to making use of D's Uniform Function Call Syntax, but I'm getting an error if I try to convert this line: createSet(createVector(langSize, index)).length; which works, into this line: createVector(langSize, index).createSet.length; receiving the error "Error: no property createSet for type int[]", when the signature for createSet is: static auto createSet(in int[] vector) pure What am I missing here? I'm sure it's stupidly obvious but it expects one argument, so I'm just calling it without parentheses. Do you try to call member functions? UFCS only works with free functions, meaning declared at module level. https://dlang.org/spec/function.html#pseudo-member
UFCS confusion
Hello, I am nesting some function calls, and I'm pretty used to making use of D's Uniform Function Call Syntax, but I'm getting an error if I try to convert this line: createSet(createVector(langSize, index)).length; which works, into this line: createVector(langSize, index).createSet.length; receiving the error "Error: no property createSet for type int[]", when the signature for createSet is: static auto createSet(in int[] vector) pure What am I missing here? I'm sure it's stupidly obvious but it expects one argument, so I'm just calling it without parentheses.
Re: UFCS syntax I never saw before.
On Thursday, 24 May 2018 at 22:03:38 UTC, aliak wrote: It feels like the only difference between a no-arg function that is @property and one that is not is that the former could be invoked with optional parentheses and the latter should be illegal with parentheses. Edit: err... other way around!
Re: UFCS syntax I never saw before.
On Tuesday, 22 May 2018 at 14:33:20 UTC, Jonathan M Davis wrote: A free function with a single argument works just fine as a setter property. e.g. you could do something like void env(Tuple!(string, string)[] str) { // set environment variables } env = [tuple("foo", "bar")]; is perfectly legal. I question that there are many cases where such a function would be considered good design, but basically any case where it would make sense to have a function act like a global variable is currently allowed but would be disallowed if you couldn't have a setter property with only one argument. - Jonathan M Davis That can be attributed with @property if the developer intends for it to be used in that way, else should be illegal.
Re: UFCS syntax I never saw before.
On Tuesday, 22 May 2018 at 13:59:16 UTC, Steven Schveighoffer wrote: The derailed plan was to leave alone the ability to call no-arg functions without parentheses, but to REQUIRE @property to call an argument-taking function with the assignment style. See the DIP here: https://wiki.dlang.org/DIP23 Written by Walter and Andrei. I can't remember why it didn't happen. -Steve Aha. Thanks for the link! It feels like the only difference between a no-arg function that is @property and one that is not is that the former could be invoked with optional parentheses and the latter should be illegal with parentheses. Whereas an argument taking function marked as @property should probably allow read or write operations depending on whether or not it's invoked with an implicit first argument or not: @property int f(int) { ... } 1.f; // read op f = 1; // write op And to make parentheses illegal as well of course.
Re: UFCS syntax I never saw before.
On Tuesday, May 22, 2018 13:48:16 aliak via Digitalmars-d-learn wrote: > On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote: > > writeln = "foo"; > > > > is legal, and it's dumb, but it hasn't mattered much in > > practice. So, causing a bunch of code breakage in order to > > disallow it is unlikely to go over well. It would also then > > make getters and setters inconsistent in that setters would > > require @property and getters wouldn't. How much that matters > > is debatable, but it does make such a change less palatable. > > > > [...] > > Can't assignment to a function be fixed though? Are there any > cases where fixing that will cause problems for @property free > functions because they all must take more that one parameter i > assume. > > It's quite a big wart so we don't have to fix all of @property at > least, but that should be fixed if fixing it does not crap on > UFCS and @property free functions. A free function with a single argument works just fine as a setter property. e.g. you could do something like void env(Tuple!(string, string)[] str) { // set environment variables } env = [tuple("foo", "bar")]; is perfectly legal. I question that there are many cases where such a function would be considered good design, but basically any case where it would make sense to have a function act like a global variable is currently allowed but would be disallowed if you couldn't have a setter property with only one argument. - Jonathan M Davis
Re: UFCS syntax I never saw before.
On 5/22/18 9:48 AM, aliak wrote: On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote: writeln = "foo"; is legal, and it's dumb, but it hasn't mattered much in practice. So, causing a bunch of code breakage in order to disallow it is unlikely to go over well. It would also then make getters and setters inconsistent in that setters would require @property and getters wouldn't. How much that matters is debatable, but it does make such a change less palatable. [...] Can't assignment to a function be fixed though? Are there any cases where fixing that will cause problems for @property free functions because they all must take more that one parameter i assume. It's quite a big wart so we don't have to fix all of @property at least, but that should be fixed if fixing it does not crap on UFCS and @property free functions. The derailed plan was to leave alone the ability to call no-arg functions without parentheses, but to REQUIRE @property to call an argument-taking function with the assignment style. See the DIP here: https://wiki.dlang.org/DIP23 Written by Walter and Andrei. I can't remember why it didn't happen. -Steve
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote: writeln = "foo"; is legal, and it's dumb, but it hasn't mattered much in practice. So, causing a bunch of code breakage in order to disallow it is unlikely to go over well. It would also then make getters and setters inconsistent in that setters would require @property and getters wouldn't. How much that matters is debatable, but it does make such a change less palatable. [...] Can't assignment to a function be fixed though? Are there any cases where fixing that will cause problems for @property free functions because they all must take more that one parameter i assume. It's quite a big wart so we don't have to fix all of @property at least, but that should be fixed if fixing it does not crap on UFCS and @property free functions.
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 14:19:35 UTC, Steven Schveighoffer wrote: On 5/21/18 8:15 AM, SrMordred wrote: Right, so this should´n be working I think. struct SomeStruct { void foo(int); } SomeStruct s; s.foo = 10; I thought that only with @property this will work. That was the plan, but it got derailed. Whoever wrote that original line of code, they need a stern talking-to. -Steve While wearing the naughty pointy hat and sitting in a corner :p
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote: On Monday, May 21, 2018 14:00:55 ANtlord via Digitalmars-d-learn wrote: If someone wrote an good DIP on the subject, I expect that things could be accelerated, but it's not much a real paint point in practice, and the chances of @property actually ever meaning anything like it was originally intended to mean are pretty much zero. UFCS killed that. - Jonathan M Davis First of all thanks a lot for the response. It cleans something for me. I need a few time to think.
Re: UFCS syntax I never saw before.
On Monday, May 21, 2018 14:00:55 ANtlord via Digitalmars-d-learn wrote: > On Monday, 21 May 2018 at 11:38:12 UTC, SrMordred wrote: > > After all this time I saw this: > > > > writeln = iota = 5; > > > > what?? > > > > I never saw that before! > > > > This is interesting, there is something useful that i can do > > with this kind of call? > > What the hell is this? I don't figure out why are there so many > syntax features? It doesn't make the language more easier. Is it > any reason to support 2 additional cases of function calling? We > have no literal for a tuple but we call a function via 3 cases. > I'm frustrated. This particular example is a result of how property functions were originally introduced into the language, and UCFS just compounded the problem. It's also why () is optional on function calls. foo = bar; is treating foo like a setter property, and auto result = foo; is treating foo like a getter property. Heck, in foo = bar; both foo and bar could be function calls. As long as it's used intelligently, this is great, because then you can treat functions as properties. But it gets really bad when someone does something dumb like writeln = "hello"; Because this can get really dumb, @property was introduced into the language with the idea that it would be used to mark functions which were supposed to be used as properties. Then dumb stuff like writeln = "hello"; could become illegal, whereas stuff functions that were actually intended to be used as properties could continue to be used as properties. So, the clean uses would be left, and the bad uses would be illegal. Unfortunately, because moving to @property meant breaking code (even code that was using properties legitimately, since it was introduced before @property was a thing), that meant that we had to introduce @property as doing nothing and then switch to enforcing it later. Somewhere along the line, the -property flag was introduced to start enforcing it, but it only partially enforced it, and of course code continued to be written without using it. So, actually moving to enforcing everything with @property was slow. And then UFCS happened, and that pretty much killed the whole thing. The problem was twofold: 1. A number of folks just got in the habit of calling functions without parens and liked it. They would generally agree that writeln = "foo"; was dumb, but they liked being able to just not use parens when doing stuff like myObj = foo; or myFunc(foo); So, telling them that they couldn't do that anymore didn't go over well. 2. Once, UFCS came into the game, instead of having code like auto result = map!(a => a / 2)(range); you got auto result = range.map!(a => / 2)(); and you all of a sudden had a bunch of templated functions with empty parens when called, and since you already had a one set of parens for the template argument, folks thought that that was ugly. So, they started writing auto result = range.map!(a => / 2); So, requiring that they then use parens for that as they would have to if parens were required when calling all non-@property functions as had been the plan was _not_ going to go over well. It basically became completely unacceptable to require @property for property functions, and so plans to properly implement @property were dropped. The result is that @property does almost nothing (it affects what typeof does, and it affects __traits - and thus std.traits.functionAttributes - and you can't overload an @property function and a normal function, but that's pretty much it). Lots of us use it all the time to indicate what we intend to be used as a property function, but it's just documentation. Now, even if you think that calling functions with no parens is great, that still leaves us with two problems: 1. writeln = "foo"; is still legal. Maybe we could make it so that @property is required with free functions used as setters that aren't used with UFCS, but figuring out a set of rules that doesn't require putting @property on all setter functions while still disallowing the really dumb stuff isn't easy, and it's questionable that requiring @property on setters at this point is going to go over well. It's very annoying that stuff like writeln = "foo"; is legal, and it's dumb, but it hasn't mattered much in practice. So, causing a bunch of code breakage in order to disallow it is unlikely to go over well. It would also then make getters and setters inconsistent in that setters would require @property and getters wouldn't. How much that matters is debatable, but it does make such a change less palatable. 2. The other issue that @property was supposed to fix was property functions that return callables - e.g. foo could return a delegate, but the compiler has to assume that the parens on foo() are calling foo, not the delegate that it returns. So,
Re: UFCS syntax I never saw before.
"%s %s".writefln = ("foo".tuple = "bar").expand; lol
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 11:38:12 UTC, SrMordred wrote: what?? Here's another weird example: ``` void funWithUfcsAndPropertySyntax() { import std.typecons : tuple; "%s %s".writefln = ("foo".tuple = "bar").expand; } ``` source: https://github.com/Hackerpilot/Idiotmatic-D/blob/master/idiotmatic.d#L78
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 11:38:12 UTC, SrMordred wrote: After all this time I saw this: writeln = iota = 5; what?? I never saw that before! This is interesting, there is something useful that i can do with this kind of call? That's pretty cool, but at the same time this should be wiped off the face of the Earth.
Re: UFCS syntax I never saw before.
On 5/21/18 8:15 AM, SrMordred wrote: Right, so this should´n be working I think. struct SomeStruct { void foo(int); } SomeStruct s; s.foo = 10; I thought that only with @property this will work. That was the plan, but it got derailed. Whoever wrote that original line of code, they need a stern talking-to. -Steve
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 11:38:12 UTC, SrMordred wrote: After all this time I saw this: writeln = iota = 5; what?? I never saw that before! This is interesting, there is something useful that i can do with this kind of call? What the hell is this? I don't figure out why are there so many syntax features? It doesn't make the language more easier. Is it any reason to support 2 additional cases of function calling? We have no literal for a tuple but we call a function via 3 cases. I'm frustrated. D has a lot cool features, I like D, but that is one of those which make me doubt the language future. I don't play a big role in the project but I talk to all my python co-workers: "You know... so there so cool language, it's called D. It can do this and that... It supports convenient static typing so you definitely know what happens in a piece of code.". But something like this make doubt about what happens in a piece of code. There is static typing so I know that type a variable has, but I look at a method calling and I ask: "Is it data field? No. Is it property? No. Is it method? No. It's UFCS! Okay." And now I see that UFCS can works the same way as a property!
Re: UFCS syntax I never saw before.
Right, so this should´n be working I think. struct SomeStruct { void foo(int); } SomeStruct s; s.foo = 10; I thought that only with @property this will work.
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 11:38:12 UTC, SrMordred wrote: After all this time I saw this: writeln = iota = 5; what?? I never saw that before! This is interesting, there is something useful that i can do with this kind of call? I probably wouldn't use that. That wasn't what it was intended for and it's not really UFCS. It's was meant for properties that are defined as functions. struct SomeStruct { void foo(int); } SomeStruct s; s.foo = 10; It's kind of horrible syntax for what it is doing, where it isn't obvious what is happening. Writeln and iota aren't setting anything, they are just function calls that happen to be able to take one parameter.
UFCS syntax I never saw before.
After all this time I saw this: writeln = iota = 5; what?? I never saw that before! This is interesting, there is something useful that i can do with this kind of call?
Re: UFCS in generic libraries, silent hijacking, and compile errors.
On Sunday, 11 March 2018 at 15:24:31 UTC, Jonathan M Davis wrote: On Sunday, March 11, 2018 08:39:54 aliak via Digitalmars-d-learn wrote: On Saturday, 10 March 2018 at 23:00:07 UTC, Jonathan M Davis > issue in practice. That doesn't mean that it's never a > problem, but from what I've seen, it's very rarely a > problem, and it's easy to work around if you run into a > particular case where it is a problem. Ya, it's easy to work around but the caveat there is you need to realize it's happening first, and add that to that it's "rarely a problem" and well ... now it seems scary enough for this to mentioned somewhere I'd say. You're talking about a situation where you used a function whose parameters match that of a member function exactly enough that a member function gets called instead of a free function. That _can_ happen, but in most cases, there's going to be a mismatch, and you'll get a compiler error if the type defines a member function that matches the free function. I don't think that I have ever seen that happen or ever seen anyone complain about it. The only case I recall along those lines was someone who was trying to use a free function that they'd decided to call front instead of something else, and it had parameters beyond just the input range, so that programmer got compilation errors when they tried to use it in their range-based functions. Not saying it's common, just something to be aware of that is non-obvious (well it was not to me at least when I started getting in to D). It's _probably_ not going to be a problem, but if it ever is then it's going to be a very hard to detect one. And sure, the solution is to just not use ufcs to be certain, but ufcs is pretty damn appealing, which is probably why I didn't realize this at the beginning. As generic codes bases grow, the chances of this happening is certainly not 0 though. Essentially yes, though you're passing too many arguments to put. There are cases where put(output, foo) will compile while output.put(foo) will not. In particular, std.range.primitives.put will accept both individual elements to be written to the output range and ranges of elements to be written, whereas typically, an output range will be written to only accept an element at a time. It's even more extreme with output ranges of characters, because the free function put will accept different string types and convert them, and even if the programmer who designed the output range added various overloads to put for completeness, it's enough extra work to deal with all of the various character types that they probably didn't. And put also works with stuff like delegates (most frequently used with a toString that accepts an output range), which don't have member functions. So, if you write your generic code to use the member function put, it's only going to work with user-defined types that define the particular overload(s) of put that you're using in your function, whereas if you use the free function, you have more variety in the types of output ranges that your code works with, and you have more ways that you can call put (e.g. passing a range of elements instead of a single element). Ooh ouch, well that's certainly good to know about. Basically I don't see a reason why we wouldn't want the following to work: struct S { void f() {} } void f(S s, int i) {} S().f(3); // error So, are you complaining that it's an error, or you want it to be an error? As it stands, it's an error, because as far as the compiler is concerned, you tried to call a member function with an argument that it doesn't accept. Complaining that it is an error :) well, not complaining, more trying to understand why really. And I appreciate you taking the time to explain. There're a lot of points in there so here we go... If you want that code to work, then it would have to add the free function to the overload set while somehow leaving out the overloads that matches the member function, which isn't how D deals with overloading at this point. Yeah, I'd say that's an implementation detail, but the main idea would be to treat an overload set that completely fails as an undefined function so that ufcs would kick in. Your problems with put would also go away then and implementing an output range would be less of a hassle. But if it did, then you have problems as soon as the type adds another member function overload. I'm not sure I see how. The member function would win out. This is the situation now anyway, with the added (IMO) disadvantage of ufcs being unusable then. Also, if you have a free function that matches the name of a member function but where their parameters don't match, wouldn't they be unrelated functions? Well, maybe. The free function takes T as the first parameter so it's certainly related to the type. I suppose they are unrelated in the same way that: struct S {
Re: UFCS in generic libraries, silent hijacking, and compile errors.
On Sunday, March 11, 2018 08:39:54 aliak via Digitalmars-d-learn wrote: > On Saturday, 10 March 2018 at 23:00:07 UTC, Jonathan M Davis > > issue in practice. That doesn't mean that it's never a problem, > > but from what I've seen, it's very rarely a problem, and it's > > easy to work around if you run into a particular case where it > > is a problem. > > Ya, it's easy to work around but the caveat there is you need to > realize it's happening first, and add that to that it's "rarely a > problem" and well ... now it seems scary enough for this to > mentioned somewhere I'd say. You're talking about a situation where you used a function whose parameters match that of a member function exactly enough that a member function gets called instead of a free function. That _can_ happen, but in most cases, there's going to be a mismatch, and you'll get a compiler error if the type defines a member function that matches the free function. I don't think that I have ever seen that happen or ever seen anyone complain about it. The only case I recall along those lines was someone who was trying to use a free function that they'd decided to call front instead of something else, and it had parameters beyond just the input range, so that programmer got compilation errors when they tried to use it in their range-based functions. I think that this is really a theoretical concern and not a practical one. Certainly, it's really only going to potentially be an issue in library code that gets used by a ton of folks with completely unexpected types. If it's in your own code, you're usually well aware of what types are going to be used with a generic function, and proper testing would catch the rare case where there would be a problem. If you're really worried about it, then just don't use UFCS, but for better or worse, it seems to be the case that the vast majority of D programmers use UFCS all the time and don't run into problems like this. > > The one case that I am aware of where best practice is to avoid > > UFCS is with put for output ranges, but that has nothing to > > with your concerns here. Rather, it has to do with the fact > > that std.range.primitives.put has a lot of overloads for > > handling various arguments (particularly when handling ranges > > of characters), and almost no one implements their output > > ranges with all of those overloads. So, if you use put with > > UFCS, you tend to run into problems if you do anything other > > than put a single element of the exact type at a time, whereas > > the free function handles more cases (even if they ultimately > > end up calling that member function with a single argument of > > the exact type). We probably shouldn't have had the free > > function and the member function share the same name. > > Oh, can you share a short example here maybe? Not sure I followed > completely > > Is it basically: > > // if r is output range > > r.put(a, b) // don't do this? > > put(r, a, b) // but do this? > > (Cause compilation error) Essentially yes, though you're passing too many arguments to put. There are cases where put(output, foo) will compile while output.put(foo) will not. In particular, std.range.primitives.put will accept both individual elements to be written to the output range and ranges of elements to be written, whereas typically, an output range will be written to only accept an element at a time. It's even more extreme with output ranges of characters, because the free function put will accept different string types and convert them, and even if the programmer who designed the output range added various overloads to put for completeness, it's enough extra work to deal with all of the various character types that they probably didn't. And put also works with stuff like delegates (most frequently used with a toString that accepts an output range), which don't have member functions. So, if you write your generic code to use the member function put, it's only going to work with user-defined types that define the particular overload(s) of put that you're using in your function, whereas if you use the free function, you have more variety in the types of output ranges that your code works with, and you have more ways that you can call put (e.g. passing a range of elements instead of a single element). > How about if it's not part of the overload set, but is looked up > if the function does not exist in the overload set. What would > the problems there be? > > Basically I don't see a reason why we wouldn't want the following > to work: > > struct S { void f() {} } > void f(S s, int i) {} > S().f(3); // error So, are you complaining that it's an error, or you want it to be an error? As it stands, it's an error, because as far as the compiler is concerned, you tried to
Re: UFCS in generic libraries, silent hijacking, and compile errors.
On Saturday, 10 March 2018 at 23:00:07 UTC, Jonathan M Davis wrote: The idea is that the type can provide its own version of the function that is better optimized for it - e.g. it could potentially provide a member function find that is more efficient for it than std.algorithm.searching.find. That's actually the only technical reason why UFCS is superior to the normal function call syntax. I think this may have hit the nail on the spot. So basically my thinking is that if you're going to use UFCS inside a generic function where you can't know what kind of methods the type has, do not do it unless you want this particular behavior or if your intent is to use a type's known API. issue in practice. That doesn't mean that it's never a problem, but from what I've seen, it's very rarely a problem, and it's easy to work around if you run into a particular case where it is a problem. Ya, it's easy to work around but the caveat there is you need to realize it's happening first, and add that to that it's "rarely a problem" and well ... now it seems scary enough for this to mentioned somewhere I'd say. The one case that I am aware of where best practice is to avoid UFCS is with put for output ranges, but that has nothing to with your concerns here. Rather, it has to do with the fact that std.range.primitives.put has a lot of overloads for handling various arguments (particularly when handling ranges of characters), and almost no one implements their output ranges with all of those overloads. So, if you use put with UFCS, you tend to run into problems if you do anything other than put a single element of the exact type at a time, whereas the free function handles more cases (even if they ultimately end up calling that member function with a single argument of the exact type). We probably shouldn't have had the free function and the member function share the same name. Oh, can you share a short example here maybe? Not sure I followed completely Is it basically: // if r is output range r.put(a, b) // don't do this? put(r, a, b) // but do this? (Cause compilation error) Is there something I'm not seeing as to why UFCS is not part of the overload set, and is there a way other than not using UFCS to prevent the silent hijacking? If it were part of the overload set, then you have problems calling member functions, particularly because there is no way to call a member function other than with UFCS, whereas you can call free functions without UFCS, and if you _really_ want to be sure that a very specific function is called, then you can even give its entire module path when calling it. When UFCS was introduced, it was decided that having member functions always win out would cause the fewest problems. - Jonathan M Davis Ah yes, ok this makes sense. Follow up: How about if it's not part of the overload set, but is looked up if the function does not exist in the overload set. What would the problems there be? Basically I don't see a reason why we wouldn't want the following to work: struct S { void f() {} } void f(S s, int i) {} S().f(3); // error Thanks!
Re: UFCS in generic libraries, silent hijacking, and compile errors.
On Saturday, March 10, 2018 21:50:42 aliak via Digitalmars-d-learn wrote: > What are the recommended guidelines for using/not using UFCS in > writing generic libraries? > > I ask because if you have an internal generic free function that > you use on types in a generic algorithm via ufcs, then everything > works fine until the type being operated on has a member function > with a similar name. The idea is that the type can provide its own version of the function that is better optimized for it - e.g. it could potentially provide a member function find that is more efficient for it than std.algorithm.searching.find. That's actually the only technical reason why UFCS is superior to the normal function call syntax. Everything else is a matter of personal preference, though some folks prefer UFCS enough that they use it everywhere. And as long as the code isn't generic, that's usually not a problem, but using UFCS in generic code with a function that isn't well-known can risk problems if it happens to match a member function. The main reason that this isn't generally a problem is that most generic code operates on either a fairly specific subset of types or on a specific API where types implementing that API don't usually implement extra functions (in particular, ranges normally only define the range API functions, so it's rare that they have member functions that conflict with anything). But if you're worried about it or want a specific function to be called that definitely isn't a member function, then just don't use UFCS. The situation that you're concerned about is not one that seems to be much of an issue in practice. That doesn't mean that it's never a problem, but from what I've seen, it's very rarely a problem, and it's easy to work around if you run into a particular case where it is a problem. The one case that I am aware of where best practice is to avoid UFCS is with put for output ranges, but that has nothing to with your concerns here. Rather, it has to do with the fact that std.range.primitives.put has a lot of overloads for handling various arguments (particularly when handling ranges of characters), and almost no one implements their output ranges with all of those overloads. So, if you use put with UFCS, you tend to run into problems if you do anything other than put a single element of the exact type at a time, whereas the free function handles more cases (even if they ultimately end up calling that member function with a single argument of the exact type). We probably shouldn't have had the free function and the member function share the same name. > Is there something I'm not seeing as to why UFCS is not part of > the overload set, and is there a way other than not using UFCS to > prevent the silent hijacking? If it were part of the overload set, then you have problems calling member functions, particularly because there is no way to call a member function other than with UFCS, whereas you can call free functions without UFCS, and if you _really_ want to be sure that a very specific function is called, then you can even give its entire module path when calling it. When UFCS was introduced, it was decided that having member functions always win out would cause the fewest problems. - Jonathan M Davis
UFCS in generic libraries, silent hijacking, and compile errors.
What are the recommended guidelines for using/not using UFCS in writing generic libraries? I ask because if you have an internal generic free function that you use on types in a generic algorithm via ufcs, then everything works fine until the type being operated on has a member function with a similar name. If the signature matches the free function then the member function is called instead of the free function (silently) and if the signature does not match then you get a compiler error. I.e.: auto identity(T)(T t) { return t; } auto fun(T)(T t) { return t.identity; } void main() { fun(3).writeln; // ok, print 3 struct S1 {} fun(S1()).writeln; // ok, prints S1() struct S2 { int identity() { return 77; } } fun(S2()).writeln; // silent hijack, prints 77 struct S3 { int identity(int i) { return i + 2; } } fun(S3()).writeln; // compile error } So the problem is that fun wants to use a utility function that it knows about, but it turns out that T can hijack that internal, private, utility if you use ufcs. So basically, it seems like ufcs is fun until it doesn't work, and it's not really obvious that you can run in to these problems with ufcs. I feel like the last case where it's a compilation error should maybe be ok though, since the function being called is actually undefined so ufcs should kick in. The problem as I understand it is that ufcs is not part of an overload set. Making it part of it would not prevent the silent hijack, but would remove the compilation problem. Is there something I'm not seeing as to why UFCS is not part of the overload set, and is there a way other than not using UFCS to prevent the silent hijacking? Cheers - Ali
Re: As many thanks As possible to who crates D and UFCS feature
On Saturday, 13 May 2017 at 10:51:09 UTC, k-five wrote: Okay, and NOW I understood what you are trying to say. First of all I thought you got mad at me. And I became sad. My sincere apologies! Always assume the best in people :-) I am glad you asked for clarification. [...] Still I am a beginner and learner. I am too, and learners we are all. Thanks anyway. Welcome.
Re: As many thanks As possible to who crates D and UFCS feature
On Saturday, 13 May 2017 at 10:15:34 UTC, Bastiaan Veelo wrote: On Saturday, 13 May 2017 at 08:23:55 UTC, k-five wrote: [...] OK understood. [...] I am sorry for expressing myself poorly. What I meant to say is that it looked like you can write an interesting article about your experience learning and using C++ and learning and using D, comparing the two. D could come out of that comparison favourably considering 1) how long it takes to learn, 2) how much code you need to write, 3) whether there are difficulties along the way, and 4) how productive you can be (getting things done). I may have been jumping to conclusions, but it could still be an interesting read, especially for people that consider learning C++ or D. In particular the focus on UFCS is interesting, as that can be rather alien to beginners, and something you are enthusiastic about. [...] Understood. [...] Posting it here is fine. You could also have posted in the general forum, as it is more of a compliment than a question. But if you want to write more about your positive experience, then a blog article might be nice. It would reach more people, and it would maybe help some of them. If you want to do that work, then maybe Mike Parker would want to put it on the D blog, and help you polish it. Whatever you decide to do, thanks for sharing your experience here :-) Bastiaan. On Saturday, 13 May 2017 at 10:15:34 UTC, Bastiaan Veelo wrote: -- Okay, and NOW I understood what you are trying to say. First of all I thought you got mad at me. And I became sad. Since; I tell this really that I was so happy about the code in D, that I would want to share my happiness here with others and not expressing myself. Still I am a beginner and learner. Thanks anyway.
Re: As many thanks As possible to who crates D and UFCS feature
On Saturday, 13 May 2017 at 08:23:55 UTC, k-five wrote: On Friday, 12 May 2017 at 20:53:56 UTC, Bastiaan Veelo wrote: Is it safe to say that these 40 lines of D do the same as your 324 lines of C++ [1]? No. I cannot say that. Since this is not a full port of renrem in C++ to D. It was just an example in D, nothing else. OK understood. This, and your comments on the difficulties of building renrem [2] versus doing "rdmd", and the steepness of the learning curve (1 year C++ vs 2 weeks D), and the productivity (2 hours D vs ?? C++) I am not sure about understanding your purpose correctly. I think are plenty material for a nice little blog. Which English Grammar rule is used here? Sorry but I do not know! are: linking verb after think: main verb and subject! I am sorry for expressing myself poorly. What I meant to say is that it looked like you can write an interesting article about your experience learning and using C++ and learning and using D, comparing the two. D could come out of that comparison favourably considering 1) how long it takes to learn, 2) how much code you need to write, 3) whether there are difficulties along the way, and 4) how productive you can be (getting things done). I may have been jumping to conclusions, but it could still be an interesting read, especially for people that consider learning C++ or D. In particular the focus on UFCS is interesting, as that can be rather alien to beginners, and something you are enthusiastic about. I just want to say D is easy to learn and use; that is it. I have no arguing about which Language is better no not. Of course that program with C++, took me 1 month until it got ready, but in 2 days I could ported to D, since I had the already experience of implementing it. Understood. Mike Parker runs the D blog, and I think he might be interested. No need to worry about the english language, you are safe with Mike. I'll see if I can get you his attention. Sorry ... Still could not understand ... except you may want me to put such post in D blog not here, and in this case, your are right, the best way for such examples is on a blog or similar. Sorry for posting it here. Posting it here is fine. You could also have posted in the general forum, as it is more of a compliment than a question. But if you want to write more about your positive experience, then a blog article might be nice. It would reach more people, and it would maybe help some of them. If you want to do that work, then maybe Mike Parker would want to put it on the D blog, and help you polish it. Whatever you decide to do, thanks for sharing your experience here :-) Bastiaan.
Re: As many thanks As possible to who crates D and UFCS feature
On Friday, 12 May 2017 at 20:53:56 UTC, Bastiaan Veelo wrote: Is it safe to say that these 40 lines of D do the same as your 324 lines of C++ [1]? No. I cannot say that. Since this is not a full port of renrem in C++ to D. It was just an example in D, nothing else. This, and your comments on the difficulties of building renrem [2] versus doing "rdmd", and the steepness of the learning curve (1 year C++ vs 2 weeks D), and the productivity (2 hours D vs ?? C++) I am not sure about understanding your purpose correctly. I think are plenty material for a nice little blog. Which English Grammar rule is used here? Sorry but I do not know! are: linking verb after think: main verb and subject! --- I just want to say D is easy to learn and use; that is it. I have no arguing about which Language is better no not. Of course that program with C++, took me 1 month until it got ready, but in 2 days I could ported to D, since I had the already experience of implementing it. Mike Parker runs the D blog, and I think he might be interested. No need to worry about the english language, you are safe with Mike. I'll see if I can get you his attention. Sorry ... Still could not understand ... except you may want me to put such post in D blog not here, and in this case, your are right, the best way for such examples is on a blog or similar. Sorry for posting it here.
Re: As many thanks As possible to who crates D and UFCS feature
On Friday, 12 May 2017 at 21:26:01 UTC, Bastiaan Veelo wrote: On Friday, 12 May 2017 at 15:24:52 UTC, k-five wrote: A full version that I just added to my gitgub: https://github.com/k-five/dren You may like getopt[1] for command line argument parsing. https://dlang.org/phobos/std_getopt.html see also https://blog.thecybershadow.net/2014/08/05/ae-utils-funopt/ https://github.com/CyberShadow/ae/blob/master/utils/funopt.d
Re: As many thanks As possible to who crates D and UFCS feature
On Friday, 12 May 2017 at 15:24:52 UTC, k-five wrote: A full version that I just added to my gitgub: https://github.com/k-five/dren You may like getopt[1] for command line argument parsing. https://dlang.org/phobos/std_getopt.html
Re: As many thanks As possible to who crates D and UFCS feature
On Friday, 12 May 2017 at 15:24:52 UTC, k-five wrote: On Friday, 12 May 2017 at 11:10:01 UTC, k-five wrote: I was waiting for a stable version of C++17 ( standard library ) to add some features of fileSystem in C++17 to my program that wants to iterate through all files in a directory recursively. I was thinking how could I do for implementing that and add it to my program. Now after starting to learn D ( nearby 2 weeks so far ). I can do it in 6 lines! void main( string[] args ){ string[] all_file_name = dirEntries( ".", SpanMode.depth, false ) .filter!( file => !file.name.matchFirst( regex( args[ 1 ] ) ).empty() ) .filter!( file => ( args[ 2 ] == "-f" || args[ 2 ] == "-d" ? ( args[ 2 ] == "-f" ? !file.isDir : !file.isFile ) : ( !file.isSymlink ) ) ) .map!( file => file.name ) .array; foreach( string item; all_file_name ) writeln( item ); } ./bin-file '[A-Z]$' -f ---> print all files that are matched against [A-Z]$ ./bin-file '[A-Z]$' -d ---> print all directory that are matched against [A-Z]$ ./bin-file '[A-Z]$' "anything-else" ---> print both files and directory that are matched against [A-Z]$ I am so happy since after more than one year practicing in C++ and putting a collection more than 2000 examples of C++ on my github, I was not sure I could do it in 6 lines. May it is a Spam but I think it is worth it. -- May it has worth it to be an example on how great D is, in somewhere like, in the tour section or std.file or std.regex to attract others. A full version that I just added to my gitgub: https://github.com/k-five/dren Is it safe to say that these 40 lines of D do the same as your 324 lines of C++ [1]? This, and your comments on the difficulties of building renrem [2] versus doing "rdmd", and the steepness of the learning curve (1 year C++ vs 2 weeks D), and the productivity (2 hours D vs ?? C++) I think are plenty material for a nice little blog. Mike Parker runs the D blog, and I think he might be interested. No need to worry about the english language, you are safe with Mike. I'll see if I can get you his attention. [1] https://github.com/k-five/renrem [2] https://github.com/k-five/renrem/blob/master/src/README.md [3] https://dlang.org/blog/
Re: As many thanks As possible to who crates D and UFCS feature
On Friday, 12 May 2017 at 11:10:01 UTC, k-five wrote: I was waiting for a stable version of C++17 ( standard library ) to add some features of fileSystem in C++17 to my program that wants to iterate through all files in a directory recursively. I was thinking how could I do for implementing that and add it to my program. Now after starting to learn D ( nearby 2 weeks so far ). I can do it in 6 lines! void main( string[] args ){ string[] all_file_name = dirEntries( ".", SpanMode.depth, false ) .filter!( file => !file.name.matchFirst( regex( args[ 1 ] ) ).empty() ) .filter!( file => ( args[ 2 ] == "-f" || args[ 2 ] == "-d" ? ( args[ 2 ] == "-f" ? !file.isDir : !file.isFile ) : ( !file.isSymlink ) ) ) .map!( file => file.name ) .array; foreach( string item; all_file_name ) writeln( item ); } ./bin-file '[A-Z]$' -f ---> print all files that are matched against [A-Z]$ ./bin-file '[A-Z]$' -d ---> print all directory that are matched against [A-Z]$ ./bin-file '[A-Z]$' "anything-else" ---> print both files and directory that are matched against [A-Z]$ I am so happy since after more than one year practicing in C++ and putting a collection more than 2000 examples of C++ on my github, I was not sure I could do it in 6 lines. May it is a Spam but I think it is worth it. -- May it has worth it to be an example on how great D is, in somewhere like, in the tour section or std.file or std.regex to attract others. A full version that I just added to my gitgub: https://github.com/k-five/dren