digitalmars.D.announce - New library: open multi-methods
- Jean-Louis Leroy (24/24) Jul 16 2017 Hello,
- Eugene Wissner (3/27) Jul 16 2017 You may want to use ```d in your code samples in the README to
- Jean-Louis Leroy (3/3) Jul 17 2017 Thinking about it, 'openmethods' would probably be a better
- jmh530 (3/6) Jul 17 2017 Googling `multimethods` brought up more programming-related
- jmh530 (3/9) Jul 17 2017 Or you could call it omm and then just refer to open
- Jean-Louis Leroy (5/16) Jul 17 2017 Yeah that's what the omm in yomm11 means, but I am not too fond
- Jean-Louis Leroy (17/23) Jul 17 2017 Yeah, I know, but I can imagine someone casually browsing the
- jmh530 (3/6) Jul 17 2017 On the other hand, when I saw methods, my first thought was R's
- Jean-Louis Leroy (3/10) Jul 17 2017 I don't know R but after a trip to Wikipedia it looks like it.
- Jay Norwood (16/18) Jul 17 2017 R is listed as one of the languages with built-in support in this
- Jean-Louis Leroy (8/18) Jul 17 2017 For example, CLOS allows you to specialize on a value (google for
- =?UTF-8?Q?Ali_=c3=87ehreli?= (9/10) Jul 17 2017 Woot! :) I'm so happy to see this project complete.
- Jean-Louis Leroy (8/20) Jul 18 2017 Thanks :) I added another example that shows how open methods are
- Jean-Louis Leroy (4/6) Jul 18 2017 Now this is funny, after implementing that optimization
- =?UTF-8?Q?Ali_=c3=87ehreli?= (15/20) Jul 18 2017 https://github.com/jll63/methods.d/blob/master/benchmarks/source/benchma...
- jmh530 (26/28) Jul 18 2017 He might be able to at least get rid of the forward declaration
- =?UTF-8?Q?Ali_=c3=87ehreli?= (24/27) Jul 18 2017 That reminds me: Would the following be possible and better?
- Jean-Louis Leroy (11/34) Jul 18 2017 Ah, I would love to get rid of that call in main(), but think
- Jean-Louis Leroy (18/43) Jul 19 2017 OK, I think I may have found solutions to both problems. The
- jmh530 (3/5) Jul 19 2017 I prefer the original.
- jmh530 (5/12) Jul 19 2017 What if you do:
- Jean-Louis Leroy (2/15) Jul 19 2017 You mean in openmethods.d?
- jmh530 (6/15) Jul 19 2017 Yes. I haven't tried something like that, but it seems like a use
- Jean-Louis Leroy (12/28) Jul 19 2017 Among other things, the mixin introduces two functions in the
- jmh530 (4/15) Jul 19 2017 I see what you mean. It only works per thread, not per module.
- jmh530 (9/13) Jul 19 2017 Based on some of your README.md text, you may need to do static
- Jean-Louis Leroy (9/41) Jul 18 2017 There are at least problems with this. Firstly it is intrusive -
- =?UTF-8?Q?Ali_=c3=87ehreli?= (9/15) Jul 18 2017 https://github.com/jll63/methods.d/blob/master/examples/matrix/source/de...
- jmh530 (12/15) Jul 18 2017 I may not have been clear enough. My ideal solution wouldn't make
- jmh530 (5/9) Jul 18 2017 Well, I suppose the matrix interface would be saying that it can
- Jean-Louis Leroy (6/17) Jul 18 2017 Exactly. Orthogonality is essential for good composition, that is
- Jean-Louis Leroy (59/77) Jul 18 2017 I pit a method-based call against its equivalent using virtual
- Jean-Louis Leroy (4/6) Jul 19 2017 Lib is in the dub registry now. Do you have a working gdc
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/6) Jul 18 2017 Added D to the Wikipedia entry, which can be expanded. :)
- Jean-Louis Leroy (3/11) Jul 18 2017 Haha that settles it then, openmethods it is! I'll rename the
- James Dean (13/37) Jul 18 2017 Interesting. One problem I think the above approach has is adding
- Jean-Louis Leroy (6/11) Jul 19 2017 Why? I haven't tried it yet (putting together an example is one
- Jean-Louis Leroy (2/2) Jul 19 2017 openmethods is now available in the dub registry:
Hello, TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.md for an explanation of what open multi-methods are, if you are not familiar with the idea.You may also want to read my article on Code Project https://www.codeproject.com/Articles/635264/Open-Multi-Methods-for-Cplusplus11-Part-1 Earlier this year I attended Ali Çehreli's talk at C++ Now. He did a good job: I walked out with the desire to learn about D and see how it measures up against C++, especially in terms of meta-programming and language extensibility. The first programming language I learned is Forth and I did some Lisp programming, so as you can imagine, my expectations are high. As an experiment, I decided to try to port parts of my yomm11 library to D. The experience turned out to be pleasant and I ended up writing a full implementation, with some friendly help from Ali and others in the Learn forum. I think that what I have now is good enough to show. The git repo is here https://github.com/jll63/methods.d and I will post a package to the registry soon. If you have the inclination, feel free to review and comment. This is my very first D project and I certainly have missed some idioms and been clumsy at times. Jean-Louis Leroy
Jul 16 2017
On Sunday, 16 July 2017 at 17:24:17 UTC, Jean-Louis Leroy wrote:Hello, TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.md for an explanation of what open multi-methods are, if you are not familiar with the idea.You may also want to read my article on Code Project https://www.codeproject.com/Articles/635264/Open-Multi-Methods-for-Cplusplus11-Part-1 Earlier this year I attended Ali Çehreli's talk at C++ Now. He did a good job: I walked out with the desire to learn about D and see how it measures up against C++, especially in terms of meta-programming and language extensibility. The first programming language I learned is Forth and I did some Lisp programming, so as you can imagine, my expectations are high. As an experiment, I decided to try to port parts of my yomm11 library to D. The experience turned out to be pleasant and I ended up writing a full implementation, with some friendly help from Ali and others in the Learn forum. I think that what I have now is good enough to show. The git repo is here https://github.com/jll63/methods.d and I will post a package to the registry soon. If you have the inclination, feel free to review and comment. This is my very first D project and I certainly have missed some idioms and been clumsy at times. Jean-Louis LeroyYou may want to use ```d in your code samples in the README to highlight it.
Jul 16 2017
Thinking about it, 'openmethods' would probably be a better feature, i.e. polymorphism outside of classes.
Jul 17 2017
On Monday, 17 July 2017 at 20:41:05 UTC, Jean-Louis Leroy wrote:Thinking about it, 'openmethods' would probably be a better feature, i.e. polymorphism outside of classes.Googling `multimethods` brought up more programming-related topics than `openmethods`.
Jul 17 2017
On Monday, 17 July 2017 at 21:31:20 UTC, jmh530 wrote:On Monday, 17 July 2017 at 20:41:05 UTC, Jean-Louis Leroy wrote:Or you could call it omm and then just refer to open multi-methods in the documentation.Thinking about it, 'openmethods' would probably be a better feature, i.e. polymorphism outside of classes.Googling `multimethods` brought up more programming-related topics than `openmethods`.
Jul 17 2017
On Monday, 17 July 2017 at 21:32:13 UTC, jmh530 wrote:On Monday, 17 July 2017 at 21:31:20 UTC, jmh530 wrote:Yeah that's what the omm in yomm11 means, but I am not too fond of acronyms. In C++ it was the library name (-lyomm11) and also the project name but no the namespace. J-LOn Monday, 17 July 2017 at 20:41:05 UTC, Jean-Louis Leroy wrote:Or you could call it omm and then just refer to open multi-methods in the documentation.Thinking about it, 'openmethods' would probably be a better feature, i.e. polymorphism outside of classes.Googling `multimethods` brought up more programming-related topics than `openmethods`.
Jul 17 2017
On Monday, 17 July 2017 at 21:31:20 UTC, jmh530 wrote:On Monday, 17 July 2017 at 20:41:05 UTC, Jean-Louis Leroy wrote:Yeah, I know, but I can imagine someone casually browsing the registry, coming across the module and saying "multi-methods? yeah, cool, but I don't remember ever needing such a thing". Indeed "multi" is nice, but IMO "open" is much more important. It is still much more frequent to have only one virtual argument. Take the awful Visitor pattern, for example. It can be neatly replaced with an open method taking only one virtual argument (barring other considerations). 'openmultimethods' is another option but again it emphasizes 'multi'. Anyway, if I go for just 'openmethods', there are enough mentions of 'multi-methods' in the docs. I think I will rename 'methods' to 'openmethods' for the time being, but the discussion remains open. Not renaming the repo yet. Thinking about it, I should add a Visitor replacement example... J-LThinking about it, 'openmethods' would probably be a better feature, i.e. polymorphism outside of classes.Googling `multimethods` brought up more programming-related topics than `openmethods`.
Jul 17 2017
On Monday, 17 July 2017 at 22:46:02 UTC, Jean-Louis Leroy wrote:I think I will rename 'methods' to 'openmethods' for the time being, but the discussion remains open. Not renaming the repo yet.On the other hand, when I saw methods, my first thought was R's methods, which I imagine is similar if I'm not mistaken.
Jul 17 2017
On Monday, 17 July 2017 at 22:59:03 UTC, jmh530 wrote:On Monday, 17 July 2017 at 22:46:02 UTC, Jean-Louis Leroy wrote:I don't know R but after a trip to Wikipedia it looks like it. J-LI think I will rename 'methods' to 'openmethods' for the time being, but the discussion remains open. Not renaming the repo yet.On the other hand, when I saw methods, my first thought was R's methods, which I imagine is similar if I'm not mistaken.
Jul 17 2017
On Tuesday, 18 July 2017 at 00:47:04 UTC, Jean-Louis Leroy wrote:I don't know R but after a trip to Wikipedia it looks like it. J-LR is listed as one of the languages with built-in support in this wiki link. I searched for multiple dispatch because I was familiar with the similar feature in julia, and that's how they refer to it. https://en.wikipedia.org/wiki/Multiple_dispatch An excerpt statement from this wiki page is : " dynamically dispatched based on the run-time (dynamic) type or, in the more general case some other attribute, of more than one of its arguments" Based on the 'some other attribute', I wonder if the library could conceivably be extended to dispatch based on the User Defined Attribute info https://dlang.org/spec/attribute.html ('c') string s; pragma(msg, __traits(getAttributes, s)); // prints tuple('c')
Jul 17 2017
On Tuesday, 18 July 2017 at 02:22:15 UTC, Jay Norwood wrote:An excerpt statement from this wiki page is : " dynamically dispatched based on the run-time (dynamic) type or, in the more general case some other attribute, of more than one of its arguments" Based on the 'some other attribute', I wonder if the library could conceivably be extended to dispatch based on the User Defined Attribute info https://dlang.org/spec/attribute.html ('c') string s; pragma(msg, __traits(getAttributes, s)); // prints tuple('c')For example, CLOS allows you to specialize on a value (google for "eql specialize"). IIRC Clojure allows you to specify your own dispatcher. As for specializing on D attributes, I don't think it's feasible. They are a purely compile-time mechanism. In your example, the type of "s" is "string", not " ('c') string". J-L
Jul 17 2017
On 07/16/2017 10:24 AM, Jean-Louis Leroy wrote:TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.mdWoot! :) I'm so happy to see this project complete. Honestly, growing up with languages without this feature (C and C++), I've not even known that I needed this feature but your example (e.g. matrix multiplication) are very convincing. If there are enough differences compared to your C++ articles, perhaps you may consider following this up with a blog post. It would be nice to see some performance results as well like you have on your C++ articles. Ali
Jul 17 2017
On Tuesday, 18 July 2017 at 04:26:42 UTC, Ali Çehreli wrote:On 07/16/2017 10:24 AM, Jean-Louis Leroy wrote:Thanks :) I added another example that shows how open methods are a superior alternative to Visitor: https://github.com/jll63/methods.d/blob/master/examples/novisitor/source/app.dTL;DR: see herehttps://github.com/jll63/methods.d/blob/master/README.md Woot! :) I'm so happy to see this project complete. Honestly, growing up with languages without this feature (C and C++), I've not even known that I needed this feature but your example (e.g. matrix multiplication) are very convincing.If there are enough differences compared to your C++ articles, perhaps you may consider following this up with a blog post. It would be nice to see some performance results as well like you have on your C++ articles.Yes I will probably write something. You mean on the D Blog? As for performance, I have a first result: https://github.com/jll63/methods.d/blob/master/benchmarks/sour e/benchmarks.d#L122 but I still have to implement the "first argument optimization". I am working on it. J-LAli
Jul 18 2017
On Tuesday, 18 July 2017 at 07:06:10 UTC, Jean-Louis Leroy wrote:As for performance, I have a first result: https://github.com/jll63/methods.d/blob/master/benchmarks/sour e/benchmarks.d#L122 but I still have to implement the "first argument optimization". I am working on it.Now this is funny, after implementing that optimization (https://github.com/jll63/methods.d/blob/94ad5a945b3c719bd8f8402bb0aa6fda8e7a6be0/source openmethods.d#L388, https://github.com/jll63/methods.d/blob/94ad5a945b3c719bd8f8402bb0aa6fda8e7a6be0/benchmarks/sourc /benchmarks.d#L139) it runs faster with ldc2 but slower with dmd. I may be testing the limits of dmd's willingness to inline my mess ;-) J-L
Jul 18 2017
On 07/18/2017 12:06 AM, Jean-Louis Leroy wrote:Yes I will probably write something. You mean on the D Blog?Not necessarily but why not. :)As for performance, I have a first result:https://github.com/jll63/methods.d/blob/master/benchmarks/source/benchmarks.d#L122but I still have to implement the "first argument optimization". I am working on it.I could use some explanation for the results but I can for the blog article. ;) It's not surprising that ldc (and gdc) can be much better than dmd in optimization. By the way, I'm in awe of your D skills in such a short time! I'm sure there are parts of the code that can be cleaned up but it's taking advantage of many powerful features of the language. I still think the usage can be made easier but I'm not sure yet. I hope others will take a look at the code and come up with an easier interface. Perhaps they are all needed but I'm thinking about the need for forward declaration, the need for the underscore prefix, etc. Ali
Jul 18 2017
On Tuesday, 18 July 2017 at 16:57:30 UTC, Ali Çehreli wrote:Perhaps they are all needed but I'm thinking about the need for forward declaration, the need for the underscore prefix, etc.He might be able to at least get rid of the forward declaration (not sure on the underscore). The way it works now is that a class that inherits from an interface is not required in any way to implement the methods. Suppose he adds another attribute to an interface such that any class that inherits from it is required to have methods defined for specific functions. So for instance, the Matrix example might look something like trait interface Matrix { property int rows() const; property int cols() const; property double at(int i, int j) const; trait void print(); } I'm not sure this would work because anything that derives from Matrix must implement print. However, if it is possible to use the attribute to allow the derived classes to ignore print, then it might work. Alternately, if there is a way to process the interface and tell the compiler to somehow ignore the trait member functions. I don't know if it'll work, but it's an idea. Anyway, the mixin(registerMethods); could then be adjusted so that void print(virtual!Matrix m); is mixed in automatically because we now know how to construct it.
Jul 18 2017
On 07/18/2017 11:03 AM, jmh530 wrote:the mixin(registerMethods); could then be adjusted so that void print(virtual!Matrix m); is mixed in automatically because we now know how to construct it.That reminds me: Would the following be possible and better? // From void main() { updateMethods(); // ... } // To mixin(constructMethods()); void main() { // ... } constructMethods() could return the following string: string constructMethods() { return q{ shared static this() { updateMethods(); } }; } If I'm not missing something, this is better because nothing needs to be added to main and the methods are available before main starts executing (module initialization order issues still apply.). Ali
Jul 18 2017
On Tuesday, 18 July 2017 at 18:21:21 UTC, Ali Çehreli wrote:That reminds me: Would the following be possible and better? // From void main() { updateMethods(); // ... } // To mixin(constructMethods()); void main() { // ... } constructMethods() could return the following string: string constructMethods() { return q{ shared static this() { updateMethods(); } }; } If I'm not missing something, this is better because nothing needs to be added to main and the methods are available before main starts executing (module initialization order issues still apply.).Ah, I would love to get rid of that call in main(), but think beyond a one module program. The matrix example (https://github.com/jll63/methods.d/tree/master/examples/matrix/source) consists in three separate modules, plus an app, all defining specializations. They need the mixin, but if we put updateMehods() in there, it will be called many times. And it is a costly operation. Guarding the call with a flag will not work, because more methods may be registered afterwards. Unless you can think of a way the last mixin can detect it's the last? Incidentally, in yomm11 that function (it's called initialize()) has to be called before any method is called, after any shared object/DLL is loaded and after a DLL is unloaded. I still have to write the code to de-register the methods and the specializations in that case by the way... J-L J-L
Jul 18 2017
On Tuesday, 18 July 2017 at 18:21:21 UTC, Ali Çehreli wrote:On 07/18/2017 11:03 AM, jmh530 wrote:OK, I think I may have found solutions to both problems. The question is, is it too hacky? 1/ method registration Replace this: import openmethods; mixin(registerMethods); ...with: mixin(import(openmethoddecls)); ...that does the two above. Problem is, it needs -Jpath on the command line to work. Unless there is a workaround? 2/ updateMethods During static construction, I could set the dispatch tables to make all the methods call a function that does updateMethods() then re-dispatches. The cost of the first method call would be huge, but if it matters the user can still call updateMethods explicitly. Thoughts?the mixin(registerMethods); could then be adjusted so thatvoidprint(virtual!Matrix m); is mixed in automatically because wenow knowhow to construct it.That reminds me: Would the following be possible and better? // From void main() { updateMethods(); // ... } // To mixin(constructMethods()); void main() { // ... } constructMethods() could return the following string: string constructMethods() { return q{ shared static this() { updateMethods(); } }; }
Jul 19 2017
On Wednesday, 19 July 2017 at 12:29:36 UTC, Jean-Louis Leroy wrote:...that does the two above. Problem is, it needs -Jpath on the command line to work. Unless there is a workaround?I prefer the original.
Jul 19 2017
On Wednesday, 19 July 2017 at 13:35:40 UTC, jmh530 wrote:On Wednesday, 19 July 2017 at 12:29:36 UTC, Jean-Louis Leroy wrote:What if you do: shared static this(){ mixin(registerMethods); }...that does the two above. Problem is, it needs -Jpath on the command line to work. Unless there is a workaround?I prefer the original.
Jul 19 2017
On Wednesday, 19 July 2017 at 13:36:55 UTC, jmh530 wrote:On Wednesday, 19 July 2017 at 13:35:40 UTC, jmh530 wrote:You mean in openmethods.d?On Wednesday, 19 July 2017 at 12:29:36 UTC, Jean-Louis Leroy wrote:What if you do: shared static this(){ mixin(registerMethods); }...that does the two above. Problem is, it needs -Jpath on the command line to work. Unless there is a workaround?I prefer the original.
Jul 19 2017
On Wednesday, 19 July 2017 at 13:46:24 UTC, Jean-Louis Leroy wrote:Yes. I haven't tried something like that, but it seems like a use case for either static this or shared static this. https://dlang.org/spec/class.html#StaticConstructor https://dlang.org/spec/class.html#SharedStaticConstructorWhat if you do: shared static this(){ mixin(registerMethods); }You mean in openmethods.d?
Jul 19 2017
On Wednesday, 19 July 2017 at 15:33:28 UTC, jmh530 wrote:On Wednesday, 19 July 2017 at 13:46:24 UTC, Jean-Louis Leroy wrote:Among other things, the mixin introduces two functions in the module's scope: the function the user actually calls (the "dispatcher"). E.g. it creates a times(double, Matrix) when it sees a times(double, virtual!Matrix). It also declares a "discriminator" function which is used to locate which method the specializations (the method funcs) relates to (it has to deal with overloads - there are two "times" methods). This has to be done for every module that contains method declarations (virtual!) or implementations ( method). That's why it has to be a string mixin (at least until we have static foreach) and be called in the matrix etc modules, not in module openmethods.Yes. I haven't tried something like that, but it seems like a use case for either static this or shared static this. https://dlang.org/spec/class.html#StaticConstructor https://dlang.org/spec/class.html#SharedStaticConstructorWhat if you do: shared static this(){ mixin(registerMethods); }You mean in openmethods.d?
Jul 19 2017
On Wednesday, 19 July 2017 at 15:56:06 UTC, Jean-Louis Leroy wrote:Among other things, the mixin introduces two functions in the module's scope: the function the user actually calls (the "dispatcher"). E.g. it creates a times(double, Matrix) when it sees a times(double, virtual!Matrix). It also declares a "discriminator" function which is used to locate which method the specializations (the method funcs) relates to (it has to deal with overloads - there are two "times" methods). This has to be done for every module that contains method declarations (virtual!) or implementations ( method). That's why it has to be a string mixin (at least until we have static foreach) and be called in the matrix etc modules, not in module openmethods.I see what you mean. It only works per thread, not per module. What you really need is some kind of module constructor.
Jul 19 2017
On Wednesday, 19 July 2017 at 15:33:28 UTC, jmh530 wrote:Yes. I haven't tried something like that, but it seems like a use case for either static this or shared static this. https://dlang.org/spec/class.html#StaticConstructor https://dlang.org/spec/class.html#SharedStaticConstructorBased on some of your README.md text, you may need to do static this rather than shared static this for what I suggested. I don't really know, but worth investigating. I liked Ali's suggestion for mixin updateMethods. Again, not sure if it should be static this or shared static this, but if you have static this for registerMethods, then a shared static this for updateMethods may occur before that. I'm not sure how important the order is.
Jul 19 2017
On Tuesday, 18 July 2017 at 18:03:30 UTC, jmh530 wrote:On Tuesday, 18 July 2017 at 16:57:30 UTC, Ali Çehreli wrote:There are at least problems with this. Firstly it is intrusive - something I strive to avoid (although I could be 100% orthogonal only because I hijack a deprecated pointer in ClassInfo). Also, some methods may want to treat Matrix as a virtual argument, and some not. Look at https://github.com/jll63/methods.d/blob/master/examples/matrix/source/matrix.d and https://github.com/jll63/methods.d/blob/master/examples/matrix/ ource/densematrix.d They know nothing about printing. They don't want to. The matrix modules do math, the app does printing. J-LPerhaps they are all needed but I'm thinking about the need for forward declaration, the need for the underscore prefix, etc.He might be able to at least get rid of the forward declaration (not sure on the underscore). The way it works now is that a class that inherits from an interface is not required in any way to implement the methods. Suppose he adds another attribute to an interface such that any class that inherits from it is required to have methods defined for specific functions. So for instance, the Matrix example might look something like trait interface Matrix { property int rows() const; property int cols() const; property double at(int i, int j) const; trait void print(); } I'm not sure this would work because anything that derives from Matrix must implement print. However, if it is possible to use the attribute to allow the derived classes to ignore print, then it might work. Alternately, if there is a way to process the interface and tell the compiler to somehow ignore the trait member functions. I don't know if it'll work, but it's an idea. Anyway, the mixin(registerMethods); could then be adjusted so that void print(virtual!Matrix m); is mixed in automatically because we now know how to construct it.
Jul 18 2017
On 07/18/2017 12:22 PM, Jean-Louis Leroy wrote:Look athttps://github.com/jll63/methods.d/blob/master/examples/matrix/source/matrix.dandhttps://github.com/jll63/methods.d/blob/master/examples/matrix/source/densematrix.dThey know nothing about printing. They don't want to. The matrix modules do math, the app does printing.Related, our friend Luís Marques was the speaker in January 2016 here at the DLang Silicon Valley meetup. "A defense of so-called anemic domain models": https://www.meetup.com/D-Lang-Silicon-Valley/events/228027468/ I'm totally sold on the idea. Ali
Jul 18 2017
On Tuesday, 18 July 2017 at 19:22:38 UTC, Jean-Louis Leroy wrote:Look at https://github.com/jll63/methods.d/blob/master/examples/matrix/source/matrix.d and https://github.com/jll63/methods.d/blob/master/examples/matrix/ ource/densematrix.d They know nothing about printing. They don't want to. The matrix modules do math, the app does printing. J-LI may not have been clear enough. My ideal solution wouldn't make any changes to that densematrix.d file, just the interface. So I don't have any issue with the matrix modules doing the math and the app doing the printing. For instance, consider the traits in Rust https://doc.rust-lang.org/book/first-edition/traits.html My idea is like making the interfaces in D similar to the traits in Rust (or at least having the option to do something similar with them). Your method void _print(Matrix m) would be similar to impl print for Matrix in Rust. Nevertheless, I get that it may be a difficult thing to implement.
Jul 18 2017
On Tuesday, 18 July 2017 at 21:16:11 UTC, jmh530 wrote:I may not have been clear enough. My ideal solution wouldn't make any changes to that densematrix.d file, just the interface. So I don't have any issue with the matrix modules doing the math and the app doing the printing.Well, I suppose the matrix interface would be saying that it can print, so maybe not as split up as you would like. While you could define a separate interface for printing, that would require a change to densematrix.
Jul 18 2017
On Tuesday, 18 July 2017 at 21:20:04 UTC, jmh530 wrote:On Tuesday, 18 July 2017 at 21:16:11 UTC, jmh530 wrote:Exactly. Orthogonality is essential for good composition, that is the reason why OOP - well, the OOP that follows the Simula/Smalltalk tradition - failed so badly. CLOS got it right 40 years ago; Simula, Smalltalk, C++, Java, etc they all got it wrong.I may not have been clear enough. My ideal solution wouldn't make any changes to that densematrix.d file, just the interface. So I don't have any issue with the matrix modules doing the math and the app doing the printing.Well, I suppose the matrix interface would be saying that it can print, so maybe not as split up as you would like. While you could define a separate interface for printing, that would require a change to densematrix.
Jul 18 2017
On Tuesday, 18 July 2017 at 16:57:30 UTC, Ali Çehreli wrote:I pit a method-based call against its equivalent using virtual functions. First calling a virtual function via a base class is pitted against a method with one virtual parameter. Then the same but calling via an interface. Lastly, I compare double dispatch with a method with two virtual arguments. I use std.datetime.comparingBenchmark, which reports the result as time(base)/time(target). So open methods are a bit slower than ordinary virtual function calls but not that much. In the meantime I have applied a second optimization for unary methods and this brings them within 33% of an ordinary, compiler implemented vfunc call. Which is OK because the situation is highly artificial. If the function does anything, the difference will be imperceptible. I am more annoyed by double dispatch beating binary methods. I will have to look at the assembler, but it may be that the index pointer is too far from the object. To begin the real work, I need to fetch that pointer form an object. Currently it is stored in ClassInfo.deallocator, so I have to 1/ fetch the vptr 2/ fetch the ClassInfo* 3/ fetch 'deallocator'. What happens next depends on the arity. Any chance of Walter giving me a pointer in the vtable? Aside the ClassInfo*? Or at least a pointer in ClassInfo, or reassign the deallocator when it is eventually retired?As for performance, I have a first result:https://github.com/jll63/methods.d/blob/master/benchmarks/source/benchmarks.d#L122but I still have to implement the "first argumentoptimization". I amworking on it.I could use some explanation for the results but I can for the blog article. ;)It's not surprising that ldc (and gdc) can be much better than dmd in optimization.I would like to try gdc but it conflicts with ldc2 - you know, the "alias __va_list = __va_list_tag;" issue. I found suggestions via google but nothing worked for me so far.By the way, I'm in awe of your D skills in such a short time!Thanks :) I found out that D was much more natural, "predictable" than C++. The most cryptic error messages happened when I forgot the "!", IIRC.I'm sure there are parts of the code that can be cleaned up but it's taking advantage of many powerful features of the language. I still think the usage can be made easier but I'm not sure yet. I hope others will take a look at the code and come up with an easier interface. Perhaps they are all needed but I'm thinking about the need for forward declaration, the need for the underscore prefix, etc.(in reverse order) Regarding the prefix, it is needed to prevent overload resolution from trumping dynamic dispatch - see here: https://github.com/jll63/methods.d/blob/master/examples/whytheund rscore/source/app.d Allowing the same name would necessitate compiler support. As for the the forward declaration - I don't think it is possible to dispense with it. All open methods systems I know of have it (defgeneric in CLOS, defmulti in Clojure, Stroustrup's proposal...). Consider: class A { } class B : A { } class X : B { } class Y : B { } method void _foo(virtual!X x) { ... } method void _foo(virtual!Y x) { ... } What is the base method? foo(B)? foo(A)? It may well be the latter. Also don't forget that the complete specialization set is known, at the earliest, at link time. If you (arbitrarily) pick foo(B), another module may introduce a B or an A specialization. As for suggestions and advise, they are very welcome :) already got a couple of PRs. Here are the remaining questions on my mind: - the module/package name: I am pretty much set on openmethods though... - throw an exception if a method is not define for the argument set, or ambiguous: having big doubts about this. We want the possibility of nothrow methods, don't we? So I will probably call a delegate via a pointer (a la C++) which, by default, will abort(). - the method prefix: hesitating between just _ or maybe m_ ??? - replace version(explain) with debug levels?
Jul 18 2017
On Tuesday, 18 July 2017 at 04:26:42 UTC, Ali Çehreli wrote:It would be nice to see some performance results as well like you have on your C++ articles.Lib is in the dub registry now. Do you have a working gdc compiler? If yes, could you run the benchmark and post the results? Please make sure to build in release mode.
Jul 19 2017
On 07/16/2017 10:24 AM, Jean-Louis Leroy wrote:Hello, TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.mdAdded D to the Wikipedia entry, which can be expanded. :) https://en.wikipedia.org/wiki/Multiple_dispatch Ali
Jul 18 2017
On Tuesday, 18 July 2017 at 22:41:13 UTC, Ali Çehreli wrote:On 07/16/2017 10:24 AM, Jean-Louis Leroy wrote:Haha that settles it then, openmethods it is! I'll rename the repo and upload to the registry momentarily.Hello, TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.mdAdded D to the Wikipedia entry, which can be expanded. :) https://en.wikipedia.org/wiki/Multiple_dispatch Ali
Jul 18 2017
On Sunday, 16 July 2017 at 17:24:17 UTC, Jean-Louis Leroy wrote:Hello, TL;DR: see here https://github.com/jll63/methods.d/blob/master/README.md for an explanation of what open multi-methods are, if you are not familiar with the idea.You may also want to read my article on Code Project https://www.codeproject.com/Articles/635264/Open-Multi-Methods-for-Cplusplus11-Part-1 Earlier this year I attended Ali Çehreli's talk at C++ Now. He did a good job: I walked out with the desire to learn about D and see how it measures up against C++, especially in terms of meta-programming and language extensibility. The first programming language I learned is Forth and I did some Lisp programming, so as you can imagine, my expectations are high. As an experiment, I decided to try to port parts of my yomm11 library to D. The experience turned out to be pleasant and I ended up writing a full implementation, with some friendly help from Ali and others in the Learn forum. I think that what I have now is good enough to show. The git repo is here https://github.com/jll63/methods.d and I will post a package to the registry soon. If you have the inclination, feel free to review and comment. This is my very first D project and I certainly have missed some idioms and been clumsy at times. Jean-Louis LeroyInteresting. One problem I think the above approach has is adding methods after compilation. Say, a plugin adds a new derived matrix type SparseMatrix and wants to customize the addition of them. This is impossible under the current model, is it not? Would it not be possible create a sort of "externmultimethod" that mimics extern'ing a method? Basically, on the "server/host" side there is a method that can be used to add new multimethods at runtime. It takes meta data and extends the virtual table to handle dispatching it along with the other functions. The "client/plugin" side has the multimethod it wants to add to the dispatch and it does this by giving it all the needed information to do so and using the new externmultimethod method to do it.
Jul 18 2017
On Wednesday, 19 July 2017 at 06:27:40 UTC, James Dean wrote:Interesting. One problem I think the above approach has is adding methods after compilation. Say, a plugin adds a new derived matrix type SparseMatrix and wants to customize the addition of them. This is impossible under the current model, is it not?Why? I haven't tried it yet (putting together an example is one of the TODOs before v1.0.0) but I fully expect it to work. The dispatch tables are created at compile time. Just call updateMethods after loading or unloading the DLL and it should work. It does in the C++ version.
Jul 19 2017
openmethods is now available in the dub registry: https://code.dlang.org/packages/openmethods
Jul 19 2017