www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Open Methods: From C++ to D

reply Mike Parker <aldacron gmail.com> writes:
Jean-Louis Leroy posted about his open methods library here in 
the forums some time ago. Now, he's written a blog post that 
explains what open methods are, and describes the D 
implementation and how it compares to his C++ library.

The blog:
https://dlang.org/blog/2017/08/28/open-methods-from-c-to-d/

Reddit:
https://www.reddit.com/r/programming/comments/6wj0ev/open_methods_from_c_to_d/
Aug 28
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 28/08/2017 1:19 PM, Mike Parker wrote:
 Jean-Louis Leroy posted about his open methods library here in the 
 forums some time ago. Now, he's written a blog post that explains what 
 open methods are, and describes the D implementation and how it compares 
 to his C++ library.
 
 The blog:
 https://dlang.org/blog/2017/08/28/open-methods-from-c-to-d/
 
 Reddit:
 https://www.reddit.com/r/programming/comments/6wj0ev/open_methods_from_c_to_d/ 
Neat. Good to see articles in support of TypeInfo/ClassInfo! I do wish we extended it for full reflection capabilities though...
Aug 28
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Monday, 28 August 2017 at 12:31:20 UTC, rikki cattermole wrote:
 On 28/08/2017 1:19 PM, Mike Parker wrote:
 Jean-Louis Leroy posted about his open methods library here in 
 the forums some time ago. Now, he's written a blog post that 
 explains what open methods are, and describes the D 
 implementation and how it compares to his C++ library.
 
 The blog:
 https://dlang.org/blog/2017/08/28/open-methods-from-c-to-d/
 
 Reddit:
 https://www.reddit.com/r/programming/comments/6wj0ev/open_methods_from_c_to_d/
Neat. Good to see articles in support of TypeInfo/ClassInfo! I do wish we extended it for full reflection capabilities though...
Agreed. Andrei suggested using rtlInfo but AFAICT this requires building a custom druntime. It would be easy to support this method in addition to 'deallocator' and 'hash' but I suspect it would not be a very popular option. Maybe we could have a void*[] in TypeInfo and a global integer index that extensions could use to allocate entries?
Aug 28
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 28/08/2017 9:06 PM, Jean-Louis Leroy wrote:
 On Monday, 28 August 2017 at 12:31:20 UTC, rikki cattermole wrote:
 On 28/08/2017 1:19 PM, Mike Parker wrote:
 Jean-Louis Leroy posted about his open methods library here in the 
 forums some time ago. Now, he's written a blog post that explains 
 what open methods are, and describes the D implementation and how it 
 compares to his C++ library.

 The blog:
 https://dlang.org/blog/2017/08/28/open-methods-from-c-to-d/

 Reddit:
 https://www.reddit.com/r/programming/comments/6wj0ev/open_methods_from_c_to_d/ 
Neat. Good to see articles in support of TypeInfo/ClassInfo! I do wish we extended it for full reflection capabilities though...
Agreed. Andrei suggested using rtlInfo but AFAICT this requires building a custom druntime. It would be easy to support this method in addition to 'deallocator' and 'hash' but I suspect it would not be a very popular option. Maybe we could have a void*[] in TypeInfo and a global integer index that extensions could use to allocate entries?
Instead of hacking new features in, we should work on a full redesign. Clearly its needed between TypeInfo not cross the dll boundary on Windows (yay no classes!), -betterC and of course full reflection that we can do significantly better in this department.
Aug 28
prev sibling next sibling parent reply Mark <smarksc gmail.com> writes:
On Monday, 28 August 2017 at 12:19:26 UTC, Mike Parker wrote:
 Jean-Louis Leroy posted about his open methods library here in 
 the forums some time ago. Now, he's written a blog post that 
 explains what open methods are, and describes the D 
 implementation and how it compares to his C++ library.

 The blog:
 https://dlang.org/blog/2017/08/28/open-methods-from-c-to-d/

 Reddit:
 https://www.reddit.com/r/programming/comments/6wj0ev/open_methods_from_c_to_d/
Nice. This does seem superior to the visitor pattern.
Aug 29
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Aug 29
parent reply Arun Chandrasekaran <aruncxy gmail.com> writes:
On Tuesday, 29 August 2017 at 12:45:50 UTC, Jean-Louis Leroy 
wrote:
 On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Thanks for this library. Just a suggestion. Would it possible to use ` openmethod` instead of ` method`?
Aug 29
next sibling parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun Chandrasekaran 
wrote:
 On Tuesday, 29 August 2017 at 12:45:50 UTC, Jean-Louis Leroy 
 wrote:
 On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Thanks for this library. Just a suggestion. Would it possible to use ` openmethod` instead of ` method`?
Ah, I think it's a little late for that. A while ago I asked if anyone had suggestions regarding that sort of things...But now that the article has been published I think it would be a very bad idea to break all the exmaples in it. What was your rationale for `openmethod` instead of just `method`? I will push a commit tonight that will make this work: import openmethods : virtual, openmethod = method, next, registerMethods, updateMethods; // ... openmethod // implement 'kick' for dogs string _kick(Dog x) // note the underscore { return "bark"; }
Aug 30
parent reply Arun Chandrasekaran <aruncxy gmail.com> writes:
On Wednesday, 30 August 2017 at 13:35:22 UTC, Jean-Louis Leroy 
wrote:
 On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun What was 
 your rationale for `openmethod` instead of just `method`?
Just that `openmethod` precisely expresses it's intent and `method` is too generic.
Aug 30
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 14:37:14 UTC, Arun Chandrasekaran 
wrote:
 On Wednesday, 30 August 2017 at 13:35:22 UTC, Jean-Louis Leroy 
 wrote:
 On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun What was 
 your rationale for `openmethod` instead of just `method`?
Just that `openmethod` precisely expresses it's intent and `method` is too generic.
I sort of agree, and somewhat regret not picking 'openmethod'. I considered both. Also specialize. If anyone had pushed for openmethod before the article, I would almost certainly have given in. My reasoning was, I hope to promote the term 'method' as the standard name for polymorphism from outside, as opposed to vfunc. We usually say "virtual functions", rarely "virtual member functions". Membership is implicit.
Aug 30
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 30/08/2017 4:10 PM, Jean-Louis Leroy wrote:
 On Wednesday, 30 August 2017 at 14:37:14 UTC, Arun Chandrasekaran wrote:
 On Wednesday, 30 August 2017 at 13:35:22 UTC, Jean-Louis Leroy wrote:
 On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun What was your 
 rationale for `openmethod` instead of just `method`?
Just that `openmethod` precisely expresses it's intent and `method` is too generic.
I sort of agree, and somewhat regret not picking 'openmethod'. I considered both. Also specialize. If anyone had pushed for openmethod before the article, I would almost certainly have given in. My reasoning was, I hope to promote the term 'method' as the standard name for polymorphism from outside, as opposed to vfunc. We usually say "virtual functions", rarely "virtual member functions". Membership is implicit.
Rename, alias to old and have it deprecated. Keep around for a couple of releases, done!
Aug 30
parent Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 15:14:04 UTC, rikki cattermole 
wrote:
 On 30/08/2017 4:10 PM, Jean-Louis Leroy wrote:
 On Wednesday, 30 August 2017 at 14:37:14 UTC, Arun 
 Chandrasekaran wrote:
 [...]
I sort of agree, and somewhat regret not picking 'openmethod'. I considered both. Also specialize. If anyone had pushed for openmethod before the article, I would almost certainly have given in. My reasoning was, I hope to promote the term 'method' as the standard name for polymorphism from outside, as opposed to vfunc. We usually say "virtual functions", rarely "virtual member functions". Membership is implicit.
Rename, alias to old and have it deprecated. Keep around for a couple of releases, done!
Deprecated, already? :-D Hmmm maybe...Let's see if anyone speaks in favor of just method.
Aug 30
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 30 August 2017 at 15:10:03 UTC, Jean-Louis Leroy 
wrote:
 I sort of agree, and somewhat regret not picking 'openmethod'. 
 I considered both. Also  specialize. If anyone had pushed for 
  openmethod before the article, I would almost certainly have 
 given in.

 My reasoning was, I hope to promote the term 'method' as the 
 standard name for polymorphism from outside, as opposed to 
 vfunc. We usually say "virtual functions", rarely "virtual 
 member functions". Membership is implicit.
We had some discussion about what to name it in the original announce thread, but I didn't want to get too focused on bikeshedding the names and you had made good points. method is probably better than specialize. Not sure what additional information you get from openmethod, given that you're already importing from openmethods, but I don't really care that much. One thing you didn't really cover is how seamlessly interacts with normal polymorphism. For instance, what if to your first example, I add the following function (note: without method) and adjust main as below. I see no reason why this shouldn't work. But you wouldn't be able to create a string kick(Animal animal) function since that is created by the mixin. string kick(Dog dog) { return "ct bark"; } void main() { updateMethods(); import std.stdio : writeln; Animal snoopy = new Dog, hector = new Pitbull; writeln("snoopy.kick(): ", snoopy.kick()); // bark writeln("hector.kick(): ", hector.kick()); // bark an dbite Dog lassie = new Dog; writeln("lassie.kick(): ", lassie.kick()); // ct bark }
Aug 30
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 15:42:09 UTC, jmh530 wrote:
 One thing you didn't really cover is how seamlessly interacts 
 with normal polymorphism. For instance, what if to your first 
 example, I add the following function (note: without  method) 
 and adjust main as below. I see no reason why this shouldn't 
 work. But you wouldn't be able to create a string kick(Animal 
 animal) function since that is created by the mixin.

 string kick(Dog dog) { return "ct bark"; }

 void main()
 {
   updateMethods();
   import std.stdio : writeln;
   Animal snoopy = new Dog, hector = new Pitbull;
   writeln("snoopy.kick(): ", snoopy.kick()); // bark
   writeln("hector.kick(): ", hector.kick()); // bark an dbite
   Dog lassie = new Dog;
   writeln("lassie.kick(): ", lassie.kick()); // ct bark
 }
What happens here is that kick(Animal) is shadowed by kick(Dog). kick(Animal) is a method but it appears to the user and the compiler as an ordinary function - which is generally good. As such it is eligible for UFCS. I would not recommend this sort of coding, but it's everyone's choice, methods or not. Likewise, methods can be overloaded (like here https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12). A current limitation is that default arguments are not supported (yet), although I think it's just a matter of putting the effort in. UFCS interacts nicely with methods because you can say a.plus(b) even if 'plus' is an open method.
Aug 30
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 30 August 2017 at 15:59:32 UTC, Jean-Louis Leroy 
wrote:
 What happens here is that kick(Animal) is shadowed by 
 kick(Dog). kick(Animal) is a method but it appears to the user 
 and the compiler as an ordinary function - which is generally 
 good. As such it is eligible for UFCS. I would not recommend 
 this sort of coding, but it's everyone's choice, methods or not.

 Likewise, methods can be overloaded (like here 
 https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12).

 A current limitation is that default arguments are not 
 supported (yet), although I think it's just a matter of putting 
 the effort in.

 UFCS interacts nicely with methods because you can say 
 a.plus(b) even if 'plus' is an open method.
I can submit this as an issue on the github page, but I figured I'd mention it here in case there was some easy fix. I tried installing the latest release from github. Compiling (Windows 7 on DMD with default options) the simple program below import openmethods; mixin(registerMethods); void main() { } gives me the errors: ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(970,21): Error: ca nnot implicitly convert expression h of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1076,34): Error: c annot implicitly convert expression dim of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1177,23): Error: c annot implicitly convert expression h of type ulong to uint dmd failed with exit code 1. The error at line 1076 can be fixed by changing the type of dim in the function to size_t. I couldn't fix the other errors. I tried having the hash function return size_t also, but that just causes other problems.
Aug 30
next sibling parent Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 18:16:47 UTC, jmh530 wrote:
 I tried installing the latest release from github. Compiling 
 (Windows 7 on DMD with default options) the simple program below

 import openmethods;
 mixin(registerMethods);

 void main()
 {
 }

 gives me the errors:
Gosh Windows I completely forgot about that...I'll take a look tonight.
Aug 30
prev sibling next sibling parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 18:16:47 UTC, jmh530 wrote:
 ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(970,21): Error:
ca
 nnot implicitly convert expression h of type ulong to uint
 ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1076,34): Error:
c
 annot implicitly convert expression dim of type ulong to uint
 ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1177,23): Error:
c
 annot implicitly convert expression h of type ulong to uint
 dmd failed with exit code 1.

 The error at line 1076 can be fixed by changing the type of dim 
 in the function to size_t. I couldn't fix the other errors. I 
 tried having the hash function return size_t also, but that 
 just causes other problems.
Fixed. Committed to master and it should show up in dub soon. Gosh, all that mind bending meta polymorphic mixin reflection multi-dimensional fu and then fall prey to ints and uints and size_ts. Sobering...
Aug 30
parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 30 August 2017 at 23:40:59 UTC, Jean-Louis Leroy 
wrote:
 Fixed. Committed to master and it should show up in dub soon.

 Gosh, all that mind bending meta polymorphic mixin reflection 
 multi-dimensional fu and then fall prey to ints and uints and 
 size_ts. Sobering...
Ha. Cheers.
Aug 30
prev sibling parent reply EntangledQuanta <EQ universe.com> writes:
On Wednesday, 30 August 2017 at 18:16:47 UTC, jmh530 wrote:
 On Wednesday, 30 August 2017 at 15:59:32 UTC, Jean-Louis Leroy 
 wrote:
 What happens here is that kick(Animal) is shadowed by 
 kick(Dog). kick(Animal) is a method but it appears to the user 
 and the compiler as an ordinary function - which is generally 
 good. As such it is eligible for UFCS. I would not recommend 
 this sort of coding, but it's everyone's choice, methods or 
 not.

 Likewise, methods can be overloaded (like here 
 https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12).

 A current limitation is that default arguments are not 
 supported (yet), although I think it's just a matter of 
 putting the effort in.

 UFCS interacts nicely with methods because you can say 
 a.plus(b) even if 'plus' is an open method.
I can submit this as an issue on the github page, but I figured I'd mention it here in case there was some easy fix. I tried installing the latest release from github. Compiling (Windows 7 on DMD with default options) the simple program below import openmethods; mixin(registerMethods); void main() { } gives me the errors: ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(970,21): Error: ca nnot implicitly convert expression h of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1076,34): Error: c annot implicitly convert expression dim of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1177,23): Error: c annot implicitly convert expression h of type ulong to uint dmd failed with exit code 1. The error at line 1076 can be fixed by changing the type of dim in the function to size_t. I couldn't fix the other errors. I tried having the hash function return size_t also, but that just causes other problems.
I was getting similar errors and simply added a cast(size_t)[used in the indexing, as he used ulongs for indexes rather than size_t] to all those you mention. After that I got more errors that I can't recall now but was much more cryptic. I did updateMethods and added the mixin but things wern't working so I gave up. Seems like a nice idea, although, the downside that I see is one doesn't get encapsulation.
Aug 31
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Thursday, 31 August 2017 at 20:42:36 UTC, EntangledQuanta 
wrote:
 On Wednesday, 30 August 2017 at 18:16:47 UTC, jmh530 wrote:
 On Wednesday, 30 August 2017 at 15:59:32 UTC, Jean-Louis Leroy 
 wrote:
 What happens here is that kick(Animal) is shadowed by 
 kick(Dog). kick(Animal) is a method but it appears to the 
 user and the compiler as an ordinary function - which is 
 generally good. As such it is eligible for UFCS. I would not 
 recommend this sort of coding, but it's everyone's choice, 
 methods or not.

 Likewise, methods can be overloaded (like here 
 https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12).

 A current limitation is that default arguments are not 
 supported (yet), although I think it's just a matter of 
 putting the effort in.

 UFCS interacts nicely with methods because you can say 
 a.plus(b) even if 'plus' is an open method.
I can submit this as an issue on the github page, but I figured I'd mention it here in case there was some easy fix. I tried installing the latest release from github. Compiling (Windows 7 on DMD with default options) the simple program below import openmethods; mixin(registerMethods); void main() { } gives me the errors: ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(970,21): Error: ca nnot implicitly convert expression h of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1076,34): Error: c annot implicitly convert expression dim of type ulong to uint ..\..\dubFolder\openmethods.d-1.0.0-rc.1\source\openmethods.d(1177,23): Error: c annot implicitly convert expression h of type ulong to uint dmd failed with exit code 1. The error at line 1076 can be fixed by changing the type of dim in the function to size_t. I couldn't fix the other errors. I tried having the hash function return size_t also, but that just causes other problems.
I was getting similar errors and simply added a cast(size_t)[used in the indexing, as he used ulongs for indexes rather than size_t] to all those you mention. After that I got more errors that I can't recall now but was much more cryptic. I did updateMethods and added the mixin but things wern't working so I gave up. Seems like a nice idea, although, the downside that I see is one doesn't get encapsulation.
It's fixed now, in master and in release v1.0.0-rc.2. Actually not getting encapsulation is good. With vfuncs, if you want polymorphism you get access to private parts, need it or not. And most of the time you neither need nor want it. If you need polymorphism and privileged access, you should use a vfunc but it's usually a sign of bad design, because a vfunc is meant to be overridden. And the override won't have access to the private parts so you may end up changing access from private to protected and usually trouble follows. I can imagine legitimate cases though. Fox example, the DiagonalMatrix addition example. In that case you can write a public final member function that performs addition using privileged access and call that from the 2-method 'plus'. ANother approach is to write the fvunc - or the 1-method - in terms of the public interface. Usually it's feasible and yields a better design.
Aug 31
parent reply EntangledQuanta <EQ universe.com> writes:
On Thursday, 31 August 2017 at 21:02:26 UTC, Jean-Louis Leroy 
wrote:
 On Thursday, 31 August 2017 at 20:42:36 UTC, EntangledQuanta 
 wrote:
 On Wednesday, 30 August 2017 at 18:16:47 UTC, jmh530 wrote:
 [...]
I was getting similar errors and simply added a cast(size_t)[used in the indexing, as he used ulongs for indexes rather than size_t] to all those you mention. After that I got more errors that I can't recall now but was much more cryptic. I did updateMethods and added the mixin but things wern't working so I gave up. Seems like a nice idea, although, the downside that I see is one doesn't get encapsulation.
It's fixed now, in master and in release v1.0.0-rc.2.
I'll check it out. I don't think the last errors I was getting were due to the sizing issues though, so is that all you fixed or was there some other stuff related to windows?
 Actually not getting encapsulation is good. With vfuncs, if you 
 want polymorphism you get access to private parts, need it or 
 not. And most of the time you neither need nor want it.

 If you need polymorphism and privileged access, you should use 
 a vfunc but it's usually a sign of bad design, because a vfunc 
 is meant to be overridden. And the override won't have access 
 to the private parts so you may end up changing access from 
 private to protected and usually trouble follows.

 I can imagine legitimate cases though. Fox example, the 
 DiagonalMatrix addition example. In that case you can write a 
 public final member function that performs addition using 
 privileged access and call that from the 2-method 'plus'.
Yeah, but one should always be allowed to shoot themselves in the foot. You never know when you might do it. Maybe an alligator has attached itself to your foot and is about to drag you under water?
 ANother approach is to write the fvunc - or the 1-method - in 
 terms of the public interface. Usually it's feasible and yields 
 a better design.
Aug 31
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Thursday, 31 August 2017 at 21:42:50 UTC, EntangledQuanta 
wrote:
 It's fixed now, in master and in release v1.0.0-rc.2.
I'll check it out. I don't think the last errors I was getting were due to the sizing issues though, so is that all you fixed or was there some other stuff related to windows?
Only size issues. Two lines in fact, see https://github.com/jll63/openmethods.d/commit/b63a88132e639bb23bb7 b305f4457450f865c6a but errors can cascade. I ran a few examples using the current dmd on Windows. Worked OK. It would be nice to have the Windows equivalent of dev/run-everything, maybe someone can PR me that?
 Yeah, but one should always be allowed to shoot themselves in 
 the foot.
I agree, wholeheartedly. In C++, yomm11 has macros that you can use to make a specific override or an entire method friend of a class. But alas no friendship in D.
Aug 31
parent reply EntangledQuanta <EQ universe.com> writes:
On Thursday, 31 August 2017 at 23:21:03 UTC, Jean-Louis Leroy 
wrote:
 On Thursday, 31 August 2017 at 21:42:50 UTC, EntangledQuanta 
 wrote:
 It's fixed now, in master and in release v1.0.0-rc.2.
I'll check it out. I don't think the last errors I was getting were due to the sizing issues though, so is that all you fixed or was there some other stuff related to windows?
Only size issues. Two lines in fact, see https://github.com/jll63/openmethods.d/commit/b63a88132e639bb23bb7 b305f4457450f865c6a but errors can cascade. I ran a few examples using the current dmd on Windows. Worked OK. It would be nice to have the Windows equivalent of dev/run-everything, maybe someone can PR me that?
I'll try again at some point. I haven't got around to messing with it again. I was testing it out on something and ran in to those errors, fixed them, then ran in to some more and just went a different direction. I will try to start using them more at some point as I think the concept, at least, can be useful. I haven't used it yet though to know just how useful. I like how it extends object functionality without having to mess directly with the objects. I think the more complex the project the more useful they become. What is good though is that one can mingle oop and openmethods and finding a proper balance should result in a simpler design.
 Yeah, but one should always be allowed to shoot themselves in 
 the foot.
I agree, wholeheartedly. In C++, yomm11 has macros that you can use to make a specific override or an entire method friend of a class. But alas no friendship in D.
Yeah, D does some weird things. For all it's power it just screws the pooch in certain cases that really casts a shadow on what might be a great design. Usually there are work-arounds, but they always fill like a kludge and require an excessive amount of code to do something that could be done very simple, all in the name of XXX(whatever XXX is: backwards compatibility, "safety"(no guns on the beach! PERIOD! Even if the beach is full of alligators! We don't want anyone shooting anyone else! Better that they be eaten by alligators!), or some other "excuse").
Aug 31
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Thursday, 31 August 2017 at 23:37:03 UTC, EntangledQuanta 
wrote:
 [Windows]
 I'll try again at some point. I haven't got around to messing 
 with it again.
Did you get a chance?
Sep 02
parent reply EntangledQuanta <EQ universe.com> writes:
On Saturday, 2 September 2017 at 14:04:07 UTC, Jean-Louis Leroy 
wrote:
 On Thursday, 31 August 2017 at 23:37:03 UTC, EntangledQuanta 
 wrote:
 [Windows]
 I'll try again at some point. I haven't got around to messing 
 with it again.
Did you get a chance?
I'll try real quick again. I'll have to rewrite the code as I moved on but: When I just add the mixin and update(to main) I get the error openmethods.d(1432): Error: function `main` has no members main.d-mixin-15(15): Error: CTFE failed because of previous errors in _registerMethods This is when I have the mixin(registerMethods) in a module that doesn't use any open methods. It says add once per module in the help, but I think it means once per module where open methods are used? Removing that mixin from main allows it to compile(but I haven't created any methods yet). You might look in to adding updateMethods in a static this() since it will be ran per process and do everything necessary, I think. After a few stupid bugs by me, I was able to get it to work! Pretty much a drop in replacement! I didn't do anything fancy, very basic, but it did work. It's not a real test but does show it can, for the most part, replace traditional code. Strangely enough, I had a protected member that I was using and it works, I guess because I defined the openmethod in the same module. I changed it to private and it worked too. So the issues about encapsulation I thought about before may be irrelevant as long as the openmethods are used in the same module(which is a nice feature of D). So, everything looks good on my end. Once I get around to creating something new or rewriting some old stuff I'll try to use them more and see what happens.
Sep 02
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Saturday, 2 September 2017 at 20:55:13 UTC, EntangledQuanta 
wrote:

 This is when I have the mixin(registerMethods) in a module that 
 doesn't use any open methods. It says add once per module in 
 the help, but I think it means once per module where open 
 methods are used?
Yes I meant that. The README.md says "Every module that declares methods or define implementations must include the following line". Ah yes the ddoc. I should update it. Also I think I should allow the mixin to silently do nothing in this case. Good catch.
 You might look in to adding updateMethods in a static this() 
 since it will be ran per process and do everything necessary, I 
 think.
Alas it won't work. Method registration is done via static ctors and they have to run - all of them - before updateMethods can do its work. In simple, one-module programs updateMethods in a static ctor will work, but in general it won't.
 Strangely enough, I had a protected member that I was using and 
 it works, I guess because I defined the openmethod in the same 
 module. I changed it to private and it worked too. So the 
 issues about encapsulation I thought about before may be 
 irrelevant as long as the openmethods are used in the same 
 module(which is a nice feature of D).
Neither the methods nor their overrides enjoy special privileges. Unless the override (i.e. the thing preceded by method) is a static member function? But I don't think so. Currently my code just scans the direct member of the module in which mixin(registerMethods) is called. Although I could change that, thus giving privileged access to some overrides. Could be useful for 1-methods. But anyway, probably there's something you don't notice...hmmm...can you share that code? Thanks for the feedback.
Sep 02
parent EntangledQuanta <EQ universe.com> writes:
On Saturday, 2 September 2017 at 21:16:50 UTC, Jean-Louis Leroy 
wrote:
 On Saturday, 2 September 2017 at 20:55:13 UTC, EntangledQuanta 
 wrote:

 This is when I have the mixin(registerMethods) in a module 
 that doesn't use any open methods. It says add once per module 
 in the help, but I think it means once per module where open 
 methods are used?
Yes I meant that. The README.md says "Every module that declares methods or define implementations must include the following line". Ah yes the ddoc. I should update it. Also I think I should allow the mixin to silently do nothing in this case. Good catch.
 You might look in to adding updateMethods in a static this() 
 since it will be ran per process and do everything necessary, 
 I think.
Alas it won't work. Method registration is done via static ctors and they have to run - all of them - before updateMethods can do its work. In simple, one-module programs updateMethods in a static ctor will work, but in general it won't.
hmm, surely there is a mechanism which can be used? Possibly hooking in to druntime or some other hack? Not that it's a big deal but if you could get off the dependencies then it would be a sort of "compiler solution".
 Strangely enough, I had a protected member that I was using 
 and it works, I guess because I defined the openmethod in the 
 same module. I changed it to private and it worked too. So the 
 issues about encapsulation I thought about before may be 
 irrelevant as long as the openmethods are used in the same 
 module(which is a nice feature of D).
Neither the methods nor their overrides enjoy special privileges. Unless the override (i.e. the thing preceded by method) is a static member function? But I don't think so. Currently my code just scans the direct member of the module in which mixin(registerMethods) is called. Although I could change that, thus giving privileged access to some overrides. Could be useful for 1-methods. But anyway, probably there's something you don't notice...hmmm...can you share that code?
In D, encapsulation is voided at the module level. So private members are public to the module. struct S { private int x; } void foo(S s) { writeln(s.x); } works. If foo is declared outside the module it will fail. It's like friend in C++ but automatic and per module. Pretty nice but that is about as far as it goes in D. My code was pretty simple. I couldn't share it all because it's too large, but I simply replaced a single member with an open method. It had a few lines of code. One was accessing a protected member, which I changed to private... all compiled. Then I remembered about D's encapsulation rules for the module. So that nullified my issues that I though openmethods might have. So, I think, in fact, this might be a pretty good solution to many problems. It allows extensibility without tying the methods to the classes directly. I'm still imagine encapsulation will be an issue for larger designs since the openmethods won't be defined in the same module, but I haven't used them enough to know what kinda faults will creep up yet. I haven't used openmethods enough to really see their power but hopefully with this solution I can ;) Thanks!
Sep 02
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 30 August 2017 at 15:59:32 UTC, Jean-Louis Leroy 
wrote:
 What happens here is that kick(Animal) is shadowed by 
 kick(Dog). kick(Animal) is a method but it appears to the user 
 and the compiler as an ordinary function - which is generally 
 good. As such it is eligible for UFCS. I would not recommend 
 this sort of coding, but it's everyone's choice, methods or not.

 Likewise, methods can be overloaded (like here 
 https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12).

 A current limitation is that default arguments are not 
 supported (yet), although I think it's just a matter of putting 
 the effort in.

 UFCS interacts nicely with methods because you can say 
 a.plus(b) even if 'plus' is an open method.
I had a chance to try out what I had suggested above and it behaves exactly as I would have expected (i.e. it prints the line "lassie.kick(): ctbark"). You seemed to emphasize UFCS in your response, but that really wasn't what I was intending to focus on. I just as easily could have re-written Dog as below and compiled the program and it would have printed the same thing. Similarly, any Dog or Pitbull type that call kick would return "ctbark", just Animals would return the original results. class Dog : Animal { final string kick() { return "ctbark"; } } My point is one can easily mix your openmethods's dynamic dispatch and D's static dispatch. That seems like a great thing that you could emphasize. Simply stated: if you use openmethods, you're not forced to only use openmethods. If you know the type at compile-time, then you can use it. It's only if you want to dynamically dispatch it that you would need openmethods.
Aug 31
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Thursday, 31 August 2017 at 14:52:43 UTC, jmh530 wrote:
 On Wednesday, 30 August 2017 at 15:59:32 UTC, Jean-Louis Leroy 
 wrote:
 What happens here is that kick(Animal) is shadowed by 
 kick(Dog). kick(Animal) is a method but it appears to the user 
 and the compiler as an ordinary function - which is generally 
 good. As such it is eligible for UFCS. I would not recommend 
 this sort of coding, but it's everyone's choice, methods or 
 not.

 Likewise, methods can be overloaded (like here 
 https://github.com/jll63/openmethods.d/blob/1.0.0-rc.1/examples/matrix/source/matrix.d#L12).

 A current limitation is that default arguments are not 
 supported (yet), although I think it's just a matter of 
 putting the effort in.

 UFCS interacts nicely with methods because you can say 
 a.plus(b) even if 'plus' is an open method.
I had a chance to try out what I had suggested above and it behaves exactly as I would have expected (i.e. it prints the line "lassie.kick(): ctbark"). You seemed to emphasize UFCS in your response, but that really wasn't what I was intending to focus on. I just as easily could have re-written Dog as below and compiled the program and it would have printed the same thing. Similarly, any Dog or Pitbull type that call kick would return "ctbark", just Animals would return the original results. class Dog : Animal { final string kick() { return "ctbark"; } } My point is one can easily mix your openmethods's dynamic dispatch and D's static dispatch. That seems like a great thing that you could emphasize. Simply stated: if you use openmethods, you're not forced to only use openmethods. If you know the type at compile-time, then you can use it. It's only if you want to dynamically dispatch it that you would need openmethods.
Indeed I misunderstood. Well, I am very pleased that my stuff interacts well with the rest of the language - I strive for that. However, I found that it is difficult to get people to open their mind to the idea of open methods, initially. Unless they come from Lisp, polymorphism and membership are almost indissociable for them. I often have to jump three hurdles. 1/ They're multi-methods, and I never actually had a use for that. That is why I insist so much on openness in the article, and throw multiple dispatch in as a bonus only half way through. That's also why I call them "open methods" and not "multi-methods" or "open multi-methods". 2/ It's just function overloading. Hmmm, polymorphism? But once I get past that, it's actually a good thing. People know (more or less) how overload resolution (or partial template specialization for the more expert) works. So I don't need to explain the rules governing dispatch and ambiguities in an abstract way. Usually I just say "you already know which override will be picked - it's the same as with compile-time overload resolution". 3/ This one is specific to D - UFCS gives me the same thing. Hmmm, polymorphism again? But you see why I am very careful with anything that may obscure or confuse the message. I find the interaction of open methods and UFCS particularly cool when implementing the "call chain" idiom (e.g. a.plus(b).times(c).invert()).
Aug 31
parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 31 August 2017 at 16:55:17 UTC, Jean-Louis Leroy 
wrote:
 Indeed I misunderstood.

 Well, I am very pleased that my stuff interacts well with the 
 rest of the language - I strive for that. However, I found that 
 it is difficult to get people to open their mind to the idea of 
 open methods, initially. Unless they come from Lisp, 
 polymorphism and membership are almost indissociable for them. 
 I often have to jump three hurdles.
I can see that it's a uphill battle, but there's a lot to like about it as well for those who listen. Maybe it would be a good idea to allow the method to take an argument, like method(Animal), then you could mixin string kick(virtual!Animal); without having to define kick. I think the ideal would be if you could just write something like below: string(Animal) string kick(virtual!Dog dog) { return "bark"; } but I don't really know how to get that to work.
Aug 31
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun Chandrasekaran 
wrote:
 On Tuesday, 29 August 2017 at 12:45:50 UTC, Jean-Louis Leroy 
 wrote:
 On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Thanks for this library. Just a suggestion. Would it possible to use ` openmethod` instead of ` method`?
alias openmethod = method; Atila
Aug 31
parent reply aberba <karabutaworld gmail.com> writes:
On Thursday, 31 August 2017 at 10:30:38 UTC, Atila Neves wrote:
 On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun 
 Chandrasekaran wrote:
 On Tuesday, 29 August 2017 at 12:45:50 UTC, Jean-Louis Leroy 
 wrote:
 On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Thanks for this library. Just a suggestion. Would it possible to use ` openmethod` instead of ` method`?
alias openmethod = method; Atila
What happens when there is UDA name collision? if its catastrophic, then openmethods makes it unique.
Aug 31
next sibling parent Jean-Louis Leroy <jl leroy.nyc> writes:
On Thursday, 31 August 2017 at 11:39:30 UTC, aberba wrote:
 Thanks for this library. Just a suggestion. Would it possible 
 to use ` openmethod` instead of ` method`?
alias openmethod = method; Atila
What happens when there is UDA name collision? if its catastrophic, then openmethods makes it unique.
After tightening a few screws, the library now supports static and selective imports.
Aug 31
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Thursday, 31 August 2017 at 11:39:30 UTC, aberba wrote:
 On Thursday, 31 August 2017 at 10:30:38 UTC, Atila Neves wrote:
 On Wednesday, 30 August 2017 at 04:48:11 UTC, Arun 
 Chandrasekaran wrote:
 On Tuesday, 29 August 2017 at 12:45:50 UTC, Jean-Louis Leroy 
 wrote:
 On Tuesday, 29 August 2017 at 12:09:01 UTC, Mark wrote:
 Nice. This does seem superior to the visitor pattern.
Here is another example - AST traversal: https://github.com/jll63/openmethods.d/blob/master/examples/acceptnovisitors/source/app.d
Thanks for this library. Just a suggestion. Would it possible to use ` openmethod` instead of ` method`?
alias openmethod = method; Atila
What happens when there is UDA name collision? if its catastrophic, then openmethods makes it unique.
import otherpackage: funkyMethod = openmethod; import openmethod: openmethod = method; Or use the fully qualified name. Either way, nothing that can't be dealt with by D's modules as they are now. Atila
Aug 31
parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 31 August 2017 at 13:30:27 UTC, Atila Neves wrote:
 import otherpackage: funkyMethod = openmethod;
 import openmethod: openmethod = method;

 Or use the fully qualified name. Either way, nothing that can't 
 be dealt with by D's modules as they are now.


 Atila
There are no limits to his criticism. If there are conflicts with method, then what happens when someone writes another project with openmethod as a UDA. I don't think it needs to get changed.
Aug 31
prev sibling parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
In the article it says:
 Finally, main calls updateMethods. This should be done before 
 calling any method (typically first thing in main) and each 
 time a library containing methods is dynamically loaded or 
 unloaded.
If the something has to be done at the beginning, we have a tool for that: static this (on module level). The mixin(registerMethods); at the top should therefore mix in. static this() { updateMethods(); } It's never wrong: Calling it in main, too, will at most be redundant. You can still call it manually, but for the part of main, you cannot inadvertently forget it. You can still have static this in that module as you may have multiple static this.
Aug 30
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 16:37:20 UTC, Q. Schroll wrote:
 In the article it says:
 Finally, main calls updateMethods. This should be done before 
 calling any method (typically first thing in main) and each 
 time a library containing methods is dynamically loaded or 
 unloaded.
If the something has to be done at the beginning, we have a tool for that: static this (on module level). The mixin(registerMethods); at the top should therefore mix in. static this() { updateMethods(); } It's never wrong: Calling it in main, too, will at most be redundant. You can still call it manually, but for the part of main, you cannot inadvertently forget it. You can still have static this in that module as you may have multiple static this.
We had a discussion about automating the call to updateMethods but I don't think that anybody thought of putting it in registerMethods. It might work. I'll look into it. Thanks for the suggestion...
Aug 30
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 30 August 2017 at 17:24:55 UTC, Jean-Louis Leroy 
wrote:
 We had a discussion about automating the call to updateMethods 
 but I don't think that anybody thought of putting it in 
 registerMethods. It might work. I'll look into it. Thanks for 
 the suggestion...
Ali had suggested something similar[1]. I think your concern was that it would get called multiple times, but shared static module constructors runs once a program (static module constructor runs once per thread). [1] http://forum.dlang.org/post/okljj1$ktb$1 digitalmars.com
Aug 30
parent reply Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 18:05:38 UTC, jmh530 wrote:
 On Wednesday, 30 August 2017 at 17:24:55 UTC, Jean-Louis Leroy 
 wrote:
 We had a discussion about automating the call to updateMethods 
 but I don't think that anybody thought of putting it in 
 registerMethods. It might work. I'll look into it. Thanks for 
 the suggestion...
Ali had suggested something similar[1]. I think your concern was that it would get called multiple times, but shared static module constructors runs once a program (static module constructor runs once per thread). [1] http://forum.dlang.org/post/okljj1$ktb$1 digitalmars.com
Ah yes...So the problem is that registerMethods emits static ctors that fill data structures representing the methods and the specializations. They have to run - all of them - before updateMethods. Thus, sadly Q's suggestion won't work.
Aug 30
parent Jean-Louis Leroy <jl leroy.nyc> writes:
On Wednesday, 30 August 2017 at 18:20:46 UTC, Jean-Louis Leroy 
wrote:
 On Wednesday, 30 August 2017 at 18:05:38 UTC, jmh530 wrote:
 On Wednesday, 30 August 2017 at 17:24:55 UTC, Jean-Louis Leroy 
 wrote:
 We had a discussion about automating the call to 
 updateMethods but I don't think that anybody thought of 
 putting it in registerMethods. It might work. I'll look into 
 it. Thanks for the suggestion...
Ali had suggested something similar[1]. I think your concern was that it would get called multiple times, but shared static module constructors runs once a program (static module constructor runs once per thread). [1] http://forum.dlang.org/post/okljj1$ktb$1 digitalmars.com
Ah yes...So the problem is that registerMethods emits static ctors that fill data structures representing the methods and the specializations. They have to run - all of them - before updateMethods. Thus, sadly Q's suggestion won't work.
Yes I remember now...even if we arrange to put the call to updateMethods in its own static ctor, coming after all the other static ctors, we don't know if there will be more modules with more methods afterwards. So we would have to do the updateMethods work each time, lest this module is the last. And updateMethods is costly: not only does it figure out all the dispatch tables, it also calculates a perfect hash (if mptr is used) using a random algorithm.
Aug 30