Re: DIP 1030-- Named Arguments--Formal Assessment
On Friday, 18 September 2020 at 13:39:14 UTC, Mike Parker wrote: It's from a phone call they had while they were discussing whether to approve or reject the DIP. LOL no wonder I couldn't find it.
Re: DIP 1030-- Named Arguments--Formal Assessment
On Thursday, 17 September 2020 at 12:58:06 UTC, Mike Parker wrote: So they decided that a new `std.traits` template and a corresponding `__traits` option are needed which expand into the exact function signature of another function. I have been trying to locate that specific discussion, without success so far. Help? This is of great interest to me, and I may throw in my $.02.
Re: DIP 1030-- Named Arguments--Formal Assessment
On Thursday, 17 September 2020 at 13:45:16 UTC, Mike Parker wrote: On Thursday, 17 September 2020 at 13:42:47 UTC, Jean-Louis Leroy wrote: this point I have some hope that the DIP is not damaging in the way Mike thinks. What Mike thinks appears nowhere in my post :-) OK, s/thinks/reports/ ;-)
Re: DIP 1030-- Named Arguments--Formal Assessment
On Thursday, 17 September 2020 at 13:23:38 UTC, Jean-Louis Leroy wrote: Actually, Parameters!origFun will carry storage classes, UDAs, etc for all the parameters. And Parameters!origFun[0..1] (note the two dots) will carry everything about the first parameter. The trouble begins when, for some reason, you need to manipulate the parameter at a finer level. For example, in openmethods, I need to change the type while preserving everything else. (For the rest of this post, to make things clear, I will call Parameter declarations that appear inside the function definition, and Arguments the values that are passed to a function call). I like named arguments. However, I would be greatly disappointed if: 1/ Parameters!origFun and Parameters!origFun[i..i+1] stopped working as well as they do now. 2/ The named arguments did not come with new traits (or at least is(__parameter) magic) to allow fully analyzing the parameters. That being said, does the new feature imply any change in the *parameters* themselves? I.e. are there changes in the way the function is defined, not only in the way it is called? I have not followed the discussion and just skimmed over the DIP now. I'm going to try to find time for this. However, at this point I have some hope that the DIP is not damaging in the way Mike thinks.
Re: DIP 1030-- Named Arguments--Formal Assessment
On Thursday, 17 September 2020 at 12:58:06 UTC, Mike Parker wrote: DIP 1030, "Named Arguments", has been accepted. During the assessment, Walter and Atila had a discussion regarding this particular criticism: https://forum.dlang.org/post/mailman.1117.1581368593.31109.digitalmar...@puremagic.com "Named arguments breaks this very important pattern: auto wrapper(alias origFun)(Parameters!origFun args) { // special sauce return origFun(args); }" They say that, though it's true that `Parameters!func` will not work in a wrapper, it "doesn't really work now"---default arguments and storage classes must be accounted for. This can be done with string mixins, or using a technique referred to by Jean-Louis Leroy as "refraction", both of which are clumsy. Actually, Parameters!origFun will carry storage classes, UDAs, etc for all the parameters. And Parameters!origFun[0..1] (note the two dots) will carry everything about the first parameter. The trouble begins when, for some reason, you need to manipulate the parameter at a finer level. For example, in openmethods, I need to change the type while preserving everything else.
Re: Picking function templates with __traits(getOverloads, ..., true)
On Thursday, 30 July 2020 at 00:27:49 UTC, user1234 wrote: On Wednesday, 29 July 2020 at 23:57:21 UTC, Jean-Louis Leroy wrote: This works: [...] I may be missing the obvious...or it's a compiler bug??? Yes and it's just been fixed, see https://github.com/dlang/dmd/pull/11431. So uncommenting the second times works on ~master. Ah thanks! In the meantime I realized that picking the overload at index 1 works. That's the difference between 'foo' and 'times'. Then I was 80% sure it was a bug.
Picking function templates with __traits(getOverloads, ..., true)
This works: module test; void foo(T)(T a, T b) {} void foo(T)(char a, T b) {} template InstantiateTemplateAt(alias Module, string name, int index, T...) { alias Template = __traits(getOverloads, test, name, true)[index]; alias InstantiateTemplateAt = Template!(T); } pragma(msg, typeof(InstantiateTemplateAt!(test, "foo", 1, int))); // pure nothrow @nogc @safe void(char a, int b) class Matrix(T) {} Matrix!T times(T)(Matrix!T a, T b); // Matrix!T times(T)(T a, Matrix!T b); // <-- second 'times' overload pragma(msg, typeof(InstantiateTemplateAt!(test, "times", 0, int))); // Matrix!int(Matrix!int a, int b) But if I uncomment the second 'times' function template, I get an error: templateoverloads.d(8): Error: template `test.times` matches more than one template declaration: templateoverloads.d(16): `times(T)(Matrix!T a, T b)` and templateoverloads.d(17): `times(T)(T a, Matrix!T b)` templateoverloads.d(19): Error: template instance `test.InstantiateTemplateAt!(test, "times", 0, int)` error instantiating _error_ I may be missing the obvious...or it's a compiler bug??? (not sure if this belongs to the Learn section either)
Upcoming refraction module in bolts [was: DUB project type support for Emacs Projectile]
On Monday, 15 June 2020 at 16:03:08 UTC, jmh530 wrote: On Monday, 15 June 2020 at 13:17:11 UTC, Jean-Louis Leroy wrote: [snip] Nah, I saw it. Well. My take on it has been ready for months but I had to wait for my employer's permission to publish it. They are very open-source friendly, and as a consequence there is a glut of requests for open-sourcing personal projects. I guess I am going to cancel my request... Ah. I suppose that depends implementation/performance/feature differences... No, it's just that they are essentially equivalent. I spent some time supporting InterfaceValues to immutable and const classes and objects. Not sure if he has that, I haven't played with tardy yet. OTOH I didn't bother with allocator support. On the bright side, I just got authorized to contribute my work on function refraction (currently part of openmethods) to bolts. You can see it here: https://github.com/aliak00/bolts/pull/10 I saw when you mentioned it earlier. Though it hasn't been something I've needed as yet, it's good to know that it's there. This allows the function mixins to work when they are in different modules, right? I don't see a test for that, but it might be useful to include such an example (I'm pretty sure You mean an example with two modules? I plan to write a D blog entry that walks through the pitfalls of cross-module mixing. Atila's tardy makes use of a similar functionality when they are in different modules). Actually we were in contact (and with Ali of course). I pointed him to the part of openmethods that creates functions. He has a 'refraction.d' too. I coined the term 'refraction'. ;-) It's interesting that many of the examples for refract are like refract!(F, "F") or refract!(answer, "answer"). Would something like Function refract(alias fun, string localSymbol = __traits(identifier, fun))() work for you? Not at all :-D That would return a name in the caller module. In the mixture you want to use only local names, and navigate from there. Maybe I should change all the examples, including the unit tests, to avoid giving the impression that the original function name is a good default for the localSymbol. In most cases it's not.
Re: DUB project type support for Emacs Projectile
On Sunday, 14 June 2020 at 18:49:01 UTC, jmh530 wrote: On Sunday, 14 June 2020 at 17:19:05 UTC, Jean-Louis Leroy wrote: [snip] In case you missed it, I thought you would find this interesting https://forum.dlang.org/thread/dytpsnkqnmgzniiwk...@forum.dlang.org Nah, I saw it. Well. My take on it has been ready for months but I had to wait for my employer's permission to publish it. They are very open-source friendly, and as a consequence there is a glut of requests for open-sourcing personal projects. I guess I am going to cancel my request... On the bright side, I just got authorized to contribute my work on function refraction (currently part of openmethods) to bolts. You can see it here: https://github.com/aliak00/bolts/pull/10
Re: DUB project type support for Emacs Projectile
On Sunday, 14 June 2020 at 16:04:32 UTC, Jean-Louis Leroy wrote: On Sunday, 14 June 2020 at 09:11:58 UTC, Andre Pany wrote: On Saturday, 13 June 2020 at 19:27:53 UTC, Jean-Louis Leroy wrote: On Monday, 18 November 2019 at 23:06:14 UTC, Per Nordlöw wrote: Have anybody written support for DUB project types in Emacs' projectile? See: https://www.projectile.mx/en/latest/projects/#adding-custom-project-types Normally it should be as easy as this: (projectile-register-project-type 'dub '("dub.json" "dub.sdl") :compile "dub compile" :test "dub test" :run "dub run") But it doesn't work for me and I cannot figure out why. The command is `dub build` which will build the project from the current work dir. You can set another work dir with arg `--root FOLDER` if needed. Same for `dub test` and `dub run`. Kind regards Andre `dub build` - right, sorry for that. But the real problem (and the reason why I never noticed the compile/build mistake) is that projectile deigns not recognize the project type. Yet I did try it in directories containing a dub project, IOW a `dub.json` was present. I just lived with it, entering the commands manually when I need to restart emacs (which happens maybe once in a week). I should debug this, maybe I'll do that today... OK, projectile checks for the presence of *all* the files in the list. So there: (defun projectile-dub-project-p () "Check if a project contains a dub.json or dub.sdl file." (or (projectile-verify-file "dub.json") (projectile-verify-file "dub.sdl"))) (projectile-register-project-type 'dub #'projectile-dub-project-p :compile "dub build" :test "dub test" :run "dub run")
Re: DUB project type support for Emacs Projectile
On Sunday, 14 June 2020 at 09:11:58 UTC, Andre Pany wrote: On Saturday, 13 June 2020 at 19:27:53 UTC, Jean-Louis Leroy wrote: On Monday, 18 November 2019 at 23:06:14 UTC, Per Nordlöw wrote: Have anybody written support for DUB project types in Emacs' projectile? See: https://www.projectile.mx/en/latest/projects/#adding-custom-project-types Normally it should be as easy as this: (projectile-register-project-type 'dub '("dub.json" "dub.sdl") :compile "dub compile" :test "dub test" :run "dub run") But it doesn't work for me and I cannot figure out why. The command is `dub build` which will build the project from the current work dir. You can set another work dir with arg `--root FOLDER` if needed. Same for `dub test` and `dub run`. Kind regards Andre `dub build` - right, sorry for that. But the real problem (and the reason why I never noticed the compile/build mistake) is that projectile deigns not recognize the project type. Yet I did try it in directories containing a dub project, IOW a `dub.json` was present. I just lived with it, entering the commands manually when I need to restart emacs (which happens maybe once in a week). I should debug this, maybe I'll do that today...
Re: DUB project type support for Emacs Projectile
On Monday, 18 November 2019 at 23:06:14 UTC, Per Nordlöw wrote: Have anybody written support for DUB project types in Emacs' projectile? See: https://www.projectile.mx/en/latest/projects/#adding-custom-project-types Normally it should be as easy as this: (projectile-register-project-type 'dub '("dub.json" "dub.sdl") :compile "dub compile" :test "dub test" :run "dub run") But it doesn't work for me and I cannot figure out why.
Re: Aliasing current function template instance
On Friday, 1 May 2020 at 21:05:17 UTC, Adam D. Ruppe wrote: On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote: Something I have overlooked? Any ideas? There's an old rule, that I can't find in the spec anymore but I'm still pretty sure it is there, where taking the address of a template inside a template yields the current instantiation. Then you can fetch the type of that and do some reflection off. So try this in your test rig: pragma(msg, Parameters!(typeof())); This rule was in there to ease callbacks and recursive functions iirc but it can also work with you thanks to typeof turning the runtime address back into a compile time alias. It looks like it does the trick. Thanks! Trying to add support for method templates to openmethods.
Re: Aliasing current function template instance
On Friday, 1 May 2020 at 20:43:05 UTC, Steven Schveighoffer wrote: On 5/1/20 4:28 PM, Jean-Louis Leroy wrote: Something I have overlooked? Any ideas? This trick works. No idea who came up with it: alias thisFunction = __traits(parent, {}); -Steve I think I get the idea. Alas it doesn't work inside a function template, because it returns the template, not the instance: void foo(T)(lazy T) { alias thisFunction = __traits(parent, {}); pragma(msg, thisFunction.stringof); //pragma(msg, Parameters!thisFunction); // later } void main() { foo(0); foo(""); } prints: foo(T)(lazy T) foo(T)(lazy T) Uncommenting the line that is (more or less) my real goal: aliasthisfunction.d(7): Error: template instance `std.traits.Parameters!(foo)` does not match template declaration `Parameters(func...)` with `func = (foo(T)(lazy T))` must satisfy the following constraint: ` isCallable!func`
Aliasing current function template instance
Is it possible, inside a function template, to create an alias to the instantiated function? IOW the equivalent of __FUNCTION__, but yielding an alias? The closest I came is: import std.string; import std.traits; void foo(T)(lazy T) { mixin( "alias thisFunction = ", __FUNCTION__[0..__FUNCTION__.lastIndexOf('.')], ";"); pragma(msg, Parameters!thisFunction); } void main() { foo(0); foo(""); } dmd -c aliasthisfunction.d (lazy int) (lazy string) ...but (unsurprisingly) this fails in presence of overloads. I.e. if I throw in: void foo(T)(int, T); ...then I get: aliasthisfunction.d(6): Error: template `aliasthisfunction.foo` matches more than one template declaration: aliasthisfunction.d(4): `foo(T)(lazy T)` and aliasthisfunction.d(20): `foo(T)(int, T)` ... Something I have overlooked? Any ideas?
Re: describe-d: an introspection library
On Wednesday, 22 April 2020 at 17:32:33 UTC, Stefan Koch wrote: It's going to be part of the compiler. You can look at the ... expression DIP. which Manu posted in General, for taste of where my stuff is going. I think I see the point - I am familiar with C++ variadic templates. Yes, speeding up `staticMap`, and often eliminating the need to use it, will hugely benefit meta-programming. However, that will not solve the problem of unnecessary instantiations that my example above demonstrates (it has a bug btw, the parameters should have been wrapped in a bolts.meta.AliasPack, but it doesn't alter the spirit). Thank you for the `-vcg-ast` switch! It looks like I am going to use it a lot. I am rewriting my system to express the accessors in terms of free functions taking meta-objects, instead of meta-objects containing properties. I have a hunch that that will curb instantiation, compile time and .o size.
Re: describe-d: an introspection library
On Wednesday, 22 April 2020 at 17:16:28 UTC, Stefan Koch wrote: I am working on a much more powerful and efficient meta programming system. Great! Is it going to be in a library, or part of the compiler? Can we get a preview somewhere?
Re: describe-d: an introspection library
On Wednesday, 22 April 2020 at 05:20:18 UTC, Stefan Koch wrote: On Tuesday, 21 April 2020 at 14:43:04 UTC, Jean-Louis Leroy wrote: I wonder if templates are lazily expanded. I haven't looked at the compiler's code, my guess is: maybe not. If the template gets used it gets instantiated (and cached). I did not word my question precisely, I meant: is it instantiated in its *entirety*. Consider: import std.meta; template Function(Attributes...) { enum isPure = Attributes[0]; enum isNogc = Attributes[1]; alias parameters = Attributes[2]; } template Parameter(int i) { // static assert(false); } template reflectFunction(alias Fun) { alias reflectFunction = Function!( true, true, staticMap!(Parameter, 1, 2, 3)); } void foo(); pragma(msg, reflectFunction!(foo).isPure); Is `Parameter` instantiated in this example? If I uncomment the assert, it fires. This is what gives me the impression that more is instantiated than is really used. And that is probably why reflecting runtime entities as template meta-objects with properties for all aspects of them is slow. I am way of my field of competence here, but I have the impression that speeding this up would not require a change in the language (unless it is stated that templates are greedily expanded, and common idioms rely on this). you can use the -vcg-ast switch to look at how your souce code looks "expandend". I tried compiling my example with `dmd -vcg-ast -c tmt.d` and I did got neither an AST nor an error, and the option is not in `dmd -h`, where can I read about it? They already gained traction, unfortunately. Well...Two things. I ended up developing this approach because I needed to copy function attributes, UDAs, function parameter storage classes and UDAs to a generated function. If the language, or Phobos, provided me a more direct way, trust me, I would have used it. For example, storage classes are not part of a parameter's type. OK. Now you can use `Parameter!F[0]` to declare a parameter in a new function (great!), but you cannot say `__traits(getStorageClasses, F)[0] Parameter!F[0]`. Also, one of D's selling points is that it does templates and meta-programming better. It's only natural that people use these features then (note that in C++, sorry for mentioning it, in my example Parameter would *not* be instantiated).
Function aliasing problem
I can alias a function template: T f(T)(T x) { return x; } alias g = f; int a = g(42); I can alias a static function: struct S { static int f(int i) { return i; } } alias sf = S.f; int b = sf(42); I can alias to a static function in a template instance: struct SS(T) { static T f(T i) { return i; } } alias ssi = SS!int.f; int c = ssi(42); Of course an alias can be templatized: alias SSS(T) = SS!T; I would like to combine them all, e.g.: alias sst(T) = SS!T.f; int d = sst(42); // <=> SS!int.f(42) But it fails like this: aliasstaticfunction.d(23): Error: template `aliasstaticfunction.sst` cannot deduce function from argument types `!()(int)`, candidates are: aliasstaticfunction.d(22):`sst(T)` In fact this simpler attempt fails in the same fashion: alias g2(X) = f!X; int e = g(42); aliasstaticfunction.d(25): Error: template `aliasstaticfunction.g2` cannot deduce function from argument types `!()(int)`, candidates are: aliasstaticfunction.d(24):`g2(X)` I tried with an eponymous template declaring an alias, in place of the alias template. Unsurprisingly, I get the same error (the latter is lowered to the former isn't it?). I also tried std.meta.Alias, to no avail. Is there a solution, other than building a templatized forwarder function, e.g.: T sst(T)(T i) { return SS!T.f(i); } int d = sst(42); (and this is not good anyway, as it drops function attributes, parameter storage classes, UDAs etc).
Re: describe-d: an introspection library
On Wednesday, 15 April 2020 at 08:00:12 UTC, bogdan wrote: I use a similar approach in openmethods. With the added twist that I need to re-create functions from existing functions, with some modifications (e.g. change the parameter types, add a parameter), while preserving function and parameter attributes. That inevitably leads to constructing mixin code (which I call "mixtures"), and it has to work across module boundaries (i.e. use `ReturnType!F` in the mixture, not the stringified type). See here: https://github.com/jll63/openmethods.d/blob/master/source/openmethods.d#L503, here: https://github.com/jll63/openmethods.d/blob/master/source/openmethods.d#L568 and here: https://github.com/jll63/openmethods.d/blob/master/source/bolts/reflection/metafunction.d I did not shy away from using templates and indeed there is a significant increase in compilation time. On the other hand, the code is much cleaner than a previous iteration that created the mixtures directly. If these techniques get traction, it will incite compiler developers to improve template instantiation, hopefully. I wonder if templates are lazily expanded. I haven't looked at the compiler's code, my guess is: maybe not.
Re: openmethods 1.3.0
On Monday, 20 April 2020 at 08:17:24 UTC, Robert M. Münch wrote: I just read your blog post [1] and wonder if it's still up-to-date or maybe an update would make sense? The blog post is still current. I remember that, in 2017, some were annoyed by the need to call a setup function (updateMethods). As for support for attributes, it is nice to have, but it is hardly the focus of the module. I don't think the improvements deserve a new blog entry. However, in the process of implementing support for attributes and storage classes, the internals became very ugly. Also I had a to address the same problems in a new library. Eventually I found a way of factoring the mixin generation code in a package that I am going to spin off, probably as part of bolts. But I need permission from my employer to do that. I hope to get it soon. This stuff sounds like a very fundamental concept/pattern and IMO would be a good member of Phobos. Andrei is not convinced ;-) Well at least not as part of the language, but probably not as part of Phobos either. That is not a problem. If I was granted two wishes, they would be: 1/ reallocate 'ClassInfo.deallocator' to me ;-) and 2/ add a more general feature to the language, similar to Perl's 'import' function: if a module defines a 'string imported(alias Module)' or a 'mixin template imported(alias Module)', call it in the context of the importing module. That would allow me to get rid of the 'mixin(registerMethods)' after the 'import openmethods'.
Re: openmethods 1.3.0
On Sunday, 19 April 2020 at 13:13:55 UTC, Jean-Louis Leroy wrote: You can read more about openmethods on githubL https://github.com/jll63/openmethods.d Available on DUBS here: https://code.dlang.org/packages/openmethods
openmethods 1.3.0
This release implements support for function attributes, except for `pure`. User-defined attributes on methods and method parameters are also supported. It is no longer necessary to call `updateMethods` explicitly, except after dynamically loading or unloading shared libraries. The internals got a major cleanup. All the mixin generating code has been moved to a separate set of modules, which I plan to contribute to the bolts library. You can read more about openmethods on githubL https://github.com/jll63/openmethods.d
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 18:05:39 UTC, Jean-Louis Leroy wrote: Interesting example, but all hope is not lost. `a` could (should?) be passed as an alias in __parameters. Okay I take this back...
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 17:48:06 UTC, Adam D. Ruppe wrote: On Friday, 17 April 2020 at 17:31:32 UTC, Jean-Louis Leroy wrote: Well, can't do. I need this purely at compile time, and cross-module. And the CTFE engine gets weird with it too dmd will have to fix this. But default parameters might not be possible in general at CT anyway... it is actually possible to define it to a variable. Observe: int a; void f(int arg = a) { // default arg is to use the global... import std.stdio; writeln(arg); } void main() { f(); // 0 this time a = 4; // and it can be changed at runtime! f(); // will now say 4 } Interesting example, but all hope is not lost. `a` could (should?) be passed as an alias in __parameters.
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote: void main() { import std.stdio; writeln(ParameterDefaults!f.stringof); } and it is fine. Well, can't do. I need this purely at compile time, and cross-module. That's for supporting UDAs and default parameter values in openmethods. If you want a peek at what I am up to, see here: https://github.com/jll63/openmethods.d/blob/bolts-reflection/source/bolts/reflection/metafunction.d
Re: Extracting user defined attributes on function parameters
Alas the presence of parameter UDAs breaks std.traits.ParameterDefaults: import std.traits; struct attr; void f(@attr int); pragma(msg, ParameterDefaults!f.stringof); Error: dmd -c bug.d bug.d(4): Error: undefined identifier `attr`, did you mean variable `ptr`? /home/jll/dlang/dmd-2.090.1/linux/bin64/../../src/phobos/std/traits.d(1526): Error: template instance `std.traits.ParameterDefaults!(f).Get!0LU` error instantiating /home/jll/dlang/dmd-2.090.1/linux/bin64/../../src/phobos/std/traits.d(1529): instantiated from here: `Impl!0LU` bug.d(6):instantiated from here: `ParameterDefaults!(f)` bug.d(6):while evaluating `pragma(msg, ParameterDefaults!(f).stringof)` I filed a bug report (20744). And examined the code of ParameterDefaults. I think I understand how it works, for the most part, but I haven't been able to find a fix yet. I'd like to understand why taking a slice of __parameters vs fetching the first element matters. What is the (meta?) type of __parameters[0..1]? I think I'd need to make a copy of it, minus the UDAs tucked at the beginning. But I haven't found a way of splitting it into smaller components. I tried using indexation and variadic template parameters, but it always collapses into a string. Makes me think of wave functions in quantum mechanics ;-)
Re: Extracting user defined attributes on function parameters
Thanks to both of you! As part of implementing full support for attributes in openmethods, I am developing a reflection library. That helped a lot. is() is a bit weird, but I described it in my "D Cookbook" to some success... I am going to order it...even though it is not available on Kindle ;-)
Re: Extracting user defined attributes on function parameters
On Tuesday, 14 April 2020 at 21:44:51 UTC, Adam D. Ruppe wrote: On Tuesday, 14 April 2020 at 21:35:12 UTC, Jean-Louis Leroy wrote: I can see them: There's some weird tricks to it. Check out my old blog sidebar about it here: http://dpldocs.info/this-week-in-d/Blog.Posted_2019_02_11.html#how-to-get-uda-on-a-function-param O.kay. It looks like `is` is D's Swiss army chainsaw. Yeah I never read the `is` doc properly. Now I am beginning to understand how `std.traits.Parameters` works. Thanks!
Extracting user defined attributes on function parameters
I can see them: import std.traits; struct foo; struct bar; void f(@foo int, @foo @bar @("baz") real); pragma(msg, Parameters!f); // (@(foo) int, @(tuple(tuple(foo), tuple(bar)), tuple("baz")) real) ...but I cannot find how to get hold of them: pragma(msg, (Mystery!f)[0]); // foo pragma(msg, __traits(mystery, f)[0]); // foo And besides the structure looks weird for the second argument. It's as if the UDAs were applied to one another, from left to right. I did search the documentation and google for 1/2 hour.
Is-expression and immutable interface
How comes? immutable struct Foo { } pragma(msg, is(Foo == immutable)); // true immutable interface Bar { } pragma(msg, is(Bar == immutable)); // false
Re: ./install.sh dmd broken?
On Monday, 13 August 2018 at 17:10:13 UTC, Jonathan Marler wrote: The problem is downloading "install.sh" directly to "~/dlang/install.sh". This causes the install script to think that it has already downloaded the "d-keyring.gpg" so it never downloads it, causing the "invalid signature" error. The fix is to download "install.sh" if the d-keyring is not downloaded, even if install.sh already is. Spot on! Thanks...
Re: ./install.sh dmd broken?
On Friday, 10 August 2018 at 13:52:19 UTC, bachmeier wrote: On Friday, 10 August 2018 at 13:19:21 UTC, Jean-Louis Leroy wrote: jll@euclid:~/dlang$ ./install.sh dmd Downloading and unpacking http://downloads.dlang.org/releases/2.x/2.081.1/dmd.2.081.1.linux.tar.xz # 100.0% Invalid signature http://downloads.dlang.org/releases/2.x/2.081.1/dmd.2.081.1.linux.tar.xz.sig Same problem with 'install update'. But not when installing ldc or gdc. It may be this: https://issues.dlang.org/show_bug.cgi?id=19100 Probably not. I am trying to install dmd on a new machine I got in June.
./install.sh dmd broken?
jll@euclid:~/dlang$ ./install.sh dmd Downloading and unpacking http://downloads.dlang.org/releases/2.x/2.081.1/dmd.2.081.1.linux.tar.xz # 100.0% Invalid signature http://downloads.dlang.org/releases/2.x/2.081.1/dmd.2.081.1.linux.tar.xz.sig Same problem with 'install update'. But not when installing ldc or gdc.
Re: Declaring a pointer to a function returning a ref
On Tuesday, 31 July 2018 at 21:29:26 UTC, Jean-Louis Leroy wrote: How do I declare a variable that contains a pointer to a function returning a reference? import std.stdio; int foo(return ref int a) { a = 42; return a; } ref int bar(return ref int a) { a = 42; return a; } void main() { int x; auto apf = writeln(typeid(apf)); // int function(return ref int)* int function(return ref int) xpf = auto apb = writeln(typeid(apb)); // int function(return ref int) ref* // int function(return ref int) ref xpb = // Error: no identifier for declarator `int function(return ref int)` // ref int function(return ref int) xpb = // Error: variable `castfunc.main.xpb` only parameters or `foreach` declarations can be `ref` } I know I could use `typeof() xpb = ` but I wonder if there is an explicit syntax.
Declaring a pointer to a function returning a ref
How do I declare a variable that contains a pointer to a function returning a reference? import std.stdio; int foo(return ref int a) { a = 42; return a; } ref int bar(return ref int a) { a = 42; return a; } void main() { int x; auto apf = writeln(typeid(apf)); // int function(return ref int)* int function(return ref int) xpf = auto apb = writeln(typeid(apb)); // int function(return ref int) ref* // int function(return ref int) ref xpb = // Error: no identifier for declarator `int function(return ref int)` // ref int function(return ref int) xpb = // Error: variable `castfunc.main.xpb` only parameters or `foreach` declarations can be `ref` }
Mysterious identifier in std.traits.ParameterStorageClassTuple
What is `PT` here: https://github.com/dlang/phobos/blob/master/std/traits.d#L1224 Where does it come from?
static foreach and function generation
Consider: module genfun; import std.stdio, std.format, std.traits; void foo(int a) { writeln("foo(%s)".format(a)); } void foo(int a, int b) { writeln("foo(%s, %s)".format(a, b)); } static foreach (fun; __traits(allMembers, genfun)) { static if (fun == "foo") { static if (is(typeof(__traits(getOverloads, genfun, fun { static foreach (ovl; __traits(getOverloads, genfun, fun)) { void foobar(Parameters!ovl args) { // HERE write("calling "); foo(args); // HERE } } } } } void main() { foobar(1); // calling foo(1) foobar(1, 2); // calling foo(1, 2) } Now I would like to change `foo` and `foobar` to calculated symbols where marked. I would also like to use as little string mixin as possible. I tried: static foreach (fun; __traits(allMembers, genfun)) { static if (fun == "foo") { static if (is(typeof(__traits(getOverloads, genfun, fun { static foreach (ovl; __traits(getOverloads, genfun, fun)) { void mixin(fun + "bar")(Parameters!ovl args) { // 1 write("calling "); mixin(fun)(args); // 2 } } } } } This gets me halfway there: #2 works but #1 does not. This works: static foreach (fun; __traits(allMembers, genfun)) { static if (fun == "foo") { static if (is(typeof(__traits(getOverloads, genfun, fun { static foreach (ovl; __traits(getOverloads, genfun, fun)) { void internal(Parameters!ovl args) { mixin(fun)(args); } mixin("alias %sbar = internal;".format(fun)); } } } } Does anyone see a potential problems with this? Or a better solution? I would like to avoid the alias.
Re: D mentioned in Infoworld
On Monday, 26 March 2018 at 16:13:17 UTC, Joakim wrote: On Monday, 26 March 2018 at 15:52:11 UTC, Jean-Louis Leroy wrote: ...as a "programming languages you should learn now" - albeit somewhat dismissively ;-) https://www.infoworld.com/article/3263395/application-development/the-programming-languages-you-should-learn-now.html Eh, never bad to be mentioned in articles like that, could encourage some to try D. Indeed!
D mentioned in Infoworld
...as a "programming languages you should learn now" - albeit somewhat dismissively ;-) https://www.infoworld.com/article/3263395/application-development/the-programming-languages-you-should-learn-now.html
Going from string to identifier
Here's what I am trying to do: mixin template MakeFun(string ID, int X) { int mixin(ID)() { return X; } } mixin MakeFun!("one", 1); // int one() { return 1; } Alas I get: makefunc.d(3): Error: no identifier for declarator `int` makefunc.d(3): Error: found `{` when expecting `;` makefunc.d(3): Error: declaration expected, not `return` makefunc.d(4): Error: unrecognized declaration Is there a shorter way than building the entire function definition as a string mixin? As in: mixin template MakeFun(string ID, int X) { import std.format; mixin(format("int %s() { return %s; }", ID, X)); } mixin MakeFun!("one", 1);
Re: Alias vs templates
On Wednesday, 21 February 2018 at 20:27:29 UTC, Steven Schveighoffer wrote: On 2/21/18 1:46 PM, Jean-Louis Leroy wrote: [...] I think because one is a function, which is allowed to be overloaded, the other is a symbol. But clearly, there are some liberties taken when you are overloading function templates, as overloading them works just fine. I think this may have been a patch at some point (you didn't use to be able to overload template functions with normal functions). It seems like a reasonable request that this code should work. I just discovered that this works: int baz(T)(); struct Baz { static int baz(T)(T x) { return x; } } alias baz(T) = Baz.baz!T;
Alias vs templates
I am trying to figure out a crispier syntax for templatized open methods. I am stumbling on this (see comments): // dmd -run conflict.d int foo(); struct Foo { static int foo(int x) { return x; } } alias foo = Foo.foo; // overload with an alias - OK int bar(T)(); int bar(T)(T x) { return x; } // overloaded function templates - OK int baz(T)(); struct Baz { static int baz(T)(T x) { return x; } } //alias baz = Baz.baz; // Error: alias conflict.baz conflicts with template conflict.baz(T)() at conflict.d(11) void main() { import std.stdio; writeln(foo(42)); // 42 writeln(bar(666)); // 666 } Why?
Re: nested module problem
On Sunday, 24 December 2017 at 22:17:23 UTC, Luís Marques wrote: On Saturday, 2 September 2017 at 20:03:48 UTC, Jean-Louis Leroy wrote: jll@ORAC:~/dev/d/tests/modules$ tree . ├── foo │ └── bar.d └── foo.d I think that shouldn't be allowed. You have a package foo, but use a normal module instead of foo/package.d. I'm going to file a bug on that. Monkey testing haha!
Re: Multiple inheritance D entry on rosettacode.org
On Thursday, 21 December 2017 at 04:15:14 UTC, user1234 wrote: Do you refer to static inheritance using multiple alias this ? If so, maybe you don't know yet that this feature is not implemented for now. Yes. I didn't realize it was still science fiction ;-) Ah, good think I passed the baton on this.
Multiple inheritance D entry on rosettacode.org
See http://rosettacode.org/wiki/Inheritance/Multiple#D I feel that the entry is incomplete. I am a supported of full-fledged MI, à la Common Lisp or C++, and the argument that interfaces solve most problems that MI solves, for less of a hassle, leaves me completely cold, even cynical. However, D is the first language that I have encountered that offers a real, manageable alternative to MI, as described in Andrei's book. So I think it would be good if someone - Ali? - could expand that entry a bit. I could do it but I am still a rookie in D and I prefer it to be done by someone who is more seasoned than me.
Re: Cyclic dependencies vs static constructors
On Tuesday, 19 December 2017 at 18:30:22 UTC, Luís Marques wrote: On Tuesday, 19 December 2017 at 17:43:46 UTC, Jean-Louis Leroy wrote: class Role { Role[] companies; I think he meant Company[] companies Yes thanks.
Cyclic dependencies vs static constructors
This has come up in a private discussion with Luís Marques. Consider: import std.stdio; import openmethods; mixin(registerMethods); class Company { Employee[] employees; } class Startup : Company { } class Role { Role[] companies; } class Founder : Role { } class Employee : Role { } void main() { // blah blah blah } As the program grows bigger, I want to split it into several modules, e.g. one per class or one per hierarchy. Now I have cyclic dependencies between modules because role.d must 'import company' and 'company.d' must 'import role'. It seems that at this point I have forgone a language feature: static constructors. They may be needed if I want to implement e.g. a global registry in Role and Company that tracks all the instances of the classes in their respective hierarchy. At this point the only workaround I see is to add base interfaces under Role and Company and establish the bi-directional relationship in terms of the said interfaces. ...or I can throw in that flag that allows cyclic deps in presence of static constructors. Eventually I may run into trouble. Have I overlooked something?
Re: Extending D to support per-class or per-instance user-defined metadata
I realize that I focused too much on the how, and not enough on the why. By "metadata" I mean the data that is "just there" in any object, in addition to user defined fields. An example of per-class metadata is the pointer to the the virtual function table. It is installed by the compiler or the runtime as part of object creation. It is the same for all the instances of the same class. Just like virtual functions, my openmethods library uses "method tables" and needs a way of finding the method table relevant to an object depending on its class. I want the library to work with objects of any classes, without requiring modifications to existing classes. Thus, there is a need to add that information to any object, in an orthogonal manner. Openmethods has two ways of doing this (one actually hijacks the deprecated 'deallocator' field in ClassInfo) but could profit from the ability to plant pointers right inside objects. Examples of per-object metadata could be: a reference count, a time stamp, an allocator, or the database an object was fetched from.
Extending D to support per-class or per-instance user-defined metadata
I just had a discussion with Walter, Andrei and Ali about open methods. While Andrei is not a great fan of open methods, he likes the idea of improving D to better support libraries that extend the language - of which my openmethods library is just an example. Andrei, correct me if I misrepresented your opinion in this paragraph. Part of the discussion was about a mechanism to add user-defined per-object or per-class metadata (there's another part that I will discuss in another thread). Andrei's initial suggestion is to put it in the vtable. If we know the initial size of the vtable, we can grow it to accommodate new slots. In fact we can already do something along those lines...sort of: import std.stdio; class Foo { abstract void report(); } class Bar : Foo { override void report() { writeln("I'm fine!"); } } void main() { void*[] newVtbl; auto initVtblSize = Bar.classinfo.vtbl.length; newVtbl.length = initVtblSize + 1; newVtbl[0..initVtblSize] = Bar.classinfo.vtbl[]; newVtbl[initVtblSize] = cast(void*) 0x123456; byte[] newInit = Bar.classinfo.m_init.dup; *cast(void***) newInit.ptr = newVtbl.ptr; Bar.classinfo.m_init = newInit; Foo foo = new Bar(); foo.report(); // I'm fine! writeln((*cast(void***)foo)[initVtblSize]); // 123456 } This works with dmd and gdc, not with ldc2. But it gives an idea of what the extension would like. A variant of the idea is to allocate the user slots *before* the vtable and access them via negative indices. It would be faster. Of course we would need a thread safe facility that libraries would call to obtain (and release) slots in the extended vtable, and return the index of the allocated slot(s). Thus a library would call an API to (globally) reserve a new slot; then another one to grow the vtable of the classes it targets (automatically finding and growing all the vtables is unfeasible because nested classes are not locatable via ModuleInfo). Walter also reminded me of the __monitor field so I played with it too. Here is prototype of what per-instance user defined slots could look like. import std.stdio; class Foo { } void main() { byte[] init; init.length = Foo.classinfo.m_init.length; init[] = Foo.classinfo.m_init[]; (cast(void**) init.ptr)[1] = cast(void*) 0x1234; Foo.classinfo.m_init = init; Foo foo = new Foo(); writeln((cast(void**) foo)[1]); // 1234 with dmd and gdc, null with ldc2 } This works with dmd and gdc but not with ldc2. This may be useful for implementing reference-counting schemes, Observers, etc. In both cases I use the undocumented 'm_init' field in ClassInfo. The books and docs do talk about the 'init' field that is used to initialize structs, but I have found no mention of 'm_init' for classes. Perhaps we could document it and make it mandatory that an implementation uses its content to pre-initialize objects. Also here I am using the space reserved for the '__monitor' hidden field. This is a problem because 1/ it will go away some day 2/ it is only one word. Granted, that word could store a pointer to a vector of words, where user-defined slots would live; but that would be at the cost of performance. Finally, note that if you have per-instance user slots and a way of automatically initializing them when an object is created, then you also have per-class user-defined metadata: just allocate a slot in the object, and put a pointer to the data in it. Please send in comments, especially if you are a library author and have encountered a need for this kind of thing. Eventually the discussion may lead to the drafting of a DIP.
Re: Posting in DLang Study
On Friday, 8 December 2017 at 15:57:02 UTC, Steven Schveighoffer wrote: On 12/8/17 10:47 AM, Jean-Louis Leroy wrote: I notice that all thread subjects are formatted [Dlang-study][topic] Description. Is the [Dlang-study] tag automatically added by the forum, or should I add it myself? Hmm.. I don't thing many people look at that forum. I have no idea whether [Dlang-study] is added automatically, I would expect not. -Steve Yeah last post dates from almost one year ago. Maybe not the best place to start a topic to which I want to attract library writers (it's about an API for extending/manipulating the vtable).
Posting in DLang Study
I notice that all thread subjects are formatted [Dlang-study][topic] Description. Is the [Dlang-study] tag automatically added by the forum, or should I add it myself?
Re: minimal object.d implementation that allows classes
On Friday, 8 December 2017 at 14:59:12 UTC, Jacob Carlborg wrote: On 2017-12-07 16:09, Jean-Louis Leroy wrote: This experiment is related to an ongoing discussion with Walter, Andrei and Ali on extending D with general mechanisms to better support libraries like openmethods. I will post in Studies soon. Modifying the vtable can be useful for mocking and stubbing methods as well. Indeed. The initial vtable is in read only memory, but the re-allocated one is writeable.
Re: minimal object.d implementation that allows classes
On Thursday, 7 December 2017 at 15:34:09 UTC, Steven Schveighoffer wrote: On 12/7/17 10:21 AM, Jean-Louis Leroy wrote: Bar.classinfo.vtbl.ptr[Bar.classinfo.vtbl.length] = cast(void*) 0x123456; This is a buffer overflow, why are you doing this specifically? -Steve It's not an overflow because of the call to `reserve`. It is part of an experiment related to supporting user-defined per-class metadata by extending the vtable.
Re: minimal object.d implementation that allows classes
On Thursday, 7 December 2017 at 15:09:45 UTC, Jean-Louis Leroy wrote: On Thursday, 7 December 2017 at 14:59:57 UTC, Steven Schveighoffer wrote: The object is constructed here: [...] Thanks for the pointers, you've saved me a lot of time :) On a side note however, you really shouldn't change data in a ClassInfo at all, and probably the compiler shouldn't let you! This experiment is related to an ongoing discussion with Walter, Andrei and Ali on extending D with general mechanisms to better support libraries like openmethods. I will post in Studies soon. Cool: import std.stdio; class Foo { abstract void report(); } class Bar : Foo { override void report() { writeln("I'm fine!"); } } void main() { auto oldPtr = Bar.classinfo.vtbl.ptr; Bar.classinfo.vtbl.reserve(1000); Bar.classinfo.vtbl.ptr[Bar.classinfo.vtbl.length] = cast(void*) 0x123456; writeln(oldPtr != Bar.classinfo.vtbl.ptr); // true *cast(void***) Bar.classinfo.m_init.ptr = Bar.classinfo.vtbl.ptr; Foo foo = new Bar(); writeln(oldPtr == *cast(void***)foo); // false foo.report(); // I'm fine! writeln((*cast(void***)foo)[Bar.classinfo.vtbl.length]); // 123456 }
Re: minimal object.d implementation that allows classes
On Thursday, 7 December 2017 at 14:59:57 UTC, Steven Schveighoffer wrote: The object is constructed here: [...] Thanks for the pointers, you've saved me a lot of time :) On a side note however, you really shouldn't change data in a ClassInfo at all, and probably the compiler shouldn't let you! This experiment is related to an ongoing discussion with Walter, Andrei and Ali on extending D with general mechanisms to better support libraries like openmethods. I will post in Studies soon.
Re: minimal object.d implementation that allows classes
On Thursday, 7 December 2017 at 13:08:09 UTC, Luís Marques wrote: On Thursday, 7 December 2017 at 08:59:08 UTC, Wild wrote: You could modify the one I use for PowerNex[1]. It is a hacked version of Adam D. Ruppes minimal.zip. There are only a few imports for strlen, mem{set,move,cpy}, etc. This one seems to be the one for me. For instance, typeid(ClassName) seems to work, which I need. For completeness, I had looked into minlibd but it didn't seemed compatible with LDC and difficult for me to fix, IIRC. Regarding Mike's question of what my use case is, I wanted my program to run in webassembly/asmjs. Since druntime/phobos haven't been ported to that target, I was being careful with my design to not depend on the runtime, but then I found out I love the openmethods package. So I decided to check if I could implement just enough of druntime to allow a forked version of openmethods to work. As far as I can tell that's feasible. I am currently trying to understand how the compiler and the runtime interact. ClassInfo contains a vtbl array whose ptr property is the same as the vptr found in an instance of that class. However, when I modify that pointer (e.g. by reserving 1000 more entries) and create a new instance, it still contains the old pointer. So it looks like the compiler sets the vptr without consulting the ClassInfo but somehow reflects it there. I'd appreciate if anybody can explain how it works, or sends me links to relevant info. Example: import std.stdio; class Foo { void foo() {} } void main() { auto oldPtr = Foo.classinfo.vtbl.ptr; Foo.classinfo.vtbl.reserve(1000); writeln(oldPtr != Foo.classinfo.vtbl.ptr); // true Object foo = new Foo(); writeln(oldPtr == *cast(void***)foo); // true, alas } ...at least that's what I get with dmd.
[openmethods] Support for templatized methods
Following a request from a couple of users to make it possible to use open methods and templates together, I toyed with a couple of ideas, until I discovered that the current implementation supports method and override templates already...well, almost, because there is a need to navigate around a couple of bugs (or limitations) in the various D compilers. I have an example in a branch (https://github.com/jll63/openmethods.d/tree/method-template-example) that adds a new mixin for manually registering classes - to be used for class template instantiations, which do not appear on ModuleInfo.localClasses. Apart from that the existing machinery is up to the task - although it requires some help from the user. Here is the gist of it (complete example here: https://github.com/jll63/openmethods.d/blob/method-template-example/tests/methodtemplates.d): class Matrix(T) {} class DenseMatrix(T) : Matrix!(T) {} class DiagonalMatrix(T) : Matrix!(T) {} template declareMatrixMethods(T) { mixin registerClasses!(Matrix!T); mixin registerClasses!(DenseMatrix!T); mixin registerClasses!(DiagonalMatrix!T); Matrix!T times(virtual!(Matrix!T), T); Matrix!T times(T, virtual!(Matrix!T)); } mixin(registerMethods("declareMatrixMethods!double")); mixin(registerMethods("declareMatrixMethods!int")); template matrixMethods(T) { @method DenseMatrix!T _times(Matrix!T m, T s) { return new DenseMatrix!T; } @method DenseMatrix!T _times(T s, Matrix!T m) { return new DenseMatrix!T; } @method DiagonalMatrix!T _times(DiagonalMatrix!T m, T s) { return new DiagonalMatrix!T; } @method DiagonalMatrix!T _times(T s, DiagonalMatrix!T m) { return new DiagonalMatrix!T; } } mixin(registerMethods("matrixMethods!double")); mixin(registerMethods("matrixMethods!int")); Now it would be nice if we could do away with the explicit instantiations...in theory it could be done - any time a method template is called, trigger the instantiation of all the templatized overrides -, but this is beyond the power of a library. Even with support at language level, it would probably require a pre-link phase. I am going to sleep on this a couple more times before documenting it and officially support it. I will probably add an overload to registerMethods so we can say 'registerMethods!(matrixMethods!double)'; I don't like passing types as strings very much. As always, comments and suggestions are encouraged.
Re: Compile-time reflection and templates
On Wednesday, 27 September 2017 at 20:04:42 UTC, jmh530 wrote: On Wednesday, 27 September 2017 at 19:47:32 UTC, Jean-Louis Leroy wrote: I'd like to go further: find the template arguments and the function arguments and return types. Looking at __traits and std.traits, it doesn't seem feasible, but maybe I overlooked something? You can use TemplateArgsOf https://dlang.org/phobos/std_traits.html#TemplateArgsOf to get the template arguments. For the stuff below, I think you can't just use foo, it has to be a specific foo!T. You can test if it's a function https://dlang.org/phobos/std_traits.html#isFunction You can get the Parameter and Return types https://dlang.org/phobos/std_traits.html#Parameters https://dlang.org/phobos/std_traits.html#ReturnType You can get the names of parameters https://dlang.org/phobos/std_traits.html#ParameterIdentifierTuple I am aware of these but TemplateArgsOf takes a template *instantiation* and returns the arguments. I want to reflect the *template*. Here what I am trying to achieve (for openmethods). Given: Matrix!T times(T, virtual!(Matrix!T)); ...inject, at compile time (in 'mixin(registerMethods)'), the following code: Matrix!T times(T)(T s, Matrix!T m) { return Method!("times", "deallocator", Matrix!T, T, virtual!(Matrix!T)).dispatcher(s, m); } Method!("times", "deallocator", Matrix!T, T, virtual!(Matrix!T)) times(T)(MethodTag, T s, Matrix!T m);
Compile-time reflection and templates
I can identify the templates in a module: module modtemp; import std.stdio; import std.traits; void foo(T)(T x) {} void main() { foreach (m; __traits(allMembers, modtemp)) { if (__traits(isTemplate, mixin(m))) { mixin("alias F = " ~ m ~ ";"); writeln(m); } } } // output: // foo I'd like to go further: find the template arguments and the function arguments and return types. Looking at __traits and std.traits, it doesn't seem feasible, but maybe I overlooked something?
Re: Finding class template instantiations via runtime reflection (for openmethods)
On Tuesday, 26 September 2017 at 04:55:46 UTC, b4s1L3 wrote: On Thursday, 21 September 2017 at 20:32:38 UTC, Jean-Louis Leroy wrote: [...] Yeah. You can setup a custom registry that maps names to their TypeInfo_Class. I do something similar in iz (though the real point in iz is a GC-free factory but the principle of the registry would be the the same for you) Example: --- /+ dub.sdl: name "dub_script" dependency "iz" version="0.6.0" +/ module dub_script; import iz.memory, std.stdio; class Foo(T){this(){writeln("fooDeInt");}} TypeInfo_Class[string] registry; // you need that... static this() { registerFactoryClass!(Foo!int)(registry); // ...and that, maybe with another name } void main() { auto fooDeInt = iz.memory.factory(registry, "Foo!int"); destruct(cast(Object) fooDeInt); } --- Yeah that's what I implemented yesterday (not pushed yet). I have a prototype of a solution for using open methods and templates together - although the syntax is not light: it requires guidance from the user (a la C++ explicit template instantiation).
Re: Finding class template instantiations via runtime reflection (for openmethods)
On Tuesday, 26 September 2017 at 15:59:01 UTC, Jacob Carlborg wrote: On 2017-09-25 16:24, Jean-Louis Leroy wrote: On Monday, 25 September 2017 at 14:17:13 UTC, Jacob Carlborg wrote: Of course, that's a bit of a PITA, but you would not be dependent on any bugs getting fixed or new features/improvements implemented. How do you do that? On Posix you use "dlopen", passing in null as the filename to get a handle to the current executable. Then you iterate the sections until you find the symbol table. For macOS there's this reference for the Mach-O binary format [1]. For Mach-O files there's this helper function as well [3]. [1] https://web.archive.org/web/20090901205800/http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html [2] getsectbynamefromheader_64 Ah, I suspected that. I don't want to go down that path, what of Windows? But thanks anyway...
Re: Finding class template instantiations via runtime reflection (for openmethods)
On Monday, 25 September 2017 at 14:17:13 UTC, Jacob Carlborg wrote: Of course, that's a bit of a PITA, but you would not be dependent on any bugs getting fixed or new features/improvements implemented. How do you do that?
Re: Finding class template instantiations via runtime reflection (for openmethods)
On Monday, 25 September 2017 at 13:57:55 UTC, Biotronic wrote: On Monday, 25 September 2017 at 13:45:05 UTC, Jean-Louis Leroy wrote: Thank you all for your input. I will file a bug report. Just reopen the old one: https://issues.dlang.org/show_bug.cgi?id=2484 -- Biotronic Done, thanks.
Re: Finding class template instantiations via runtime reflection (for openmethods)
Thank you all for your input. I will file a bug report.
Re: Finding class template instantiations via runtime reflection (for openmethods)
On Sunday, 24 September 2017 at 04:30:26 UTC, user1234 wrote: aliases are not symbol so it's expected that 'BarInt' doesn't appear in the items. I didn't really expect that either.
Finding class template instantiations via runtime reflection (for openmethods)
It did not take long! Someone tried to create templatized open methods and it didn't work right of the box. I expected that, but in fact there may be a bit of hope. You cannot have virtual function templates in C++ or in D because the layout of the vtables have to be known at compile time - but openmethods creates its method tables at runtime so maybe it can be made to work. I stumbled upon a problem very quickly: it seems that classes that come from class template instantiations are not registered in ModuleInfo - see below, import std.stdio; class Foo {} class Bar(T) : Foo { int i; } alias BarInt = Bar!int; const barInt = new BarInt; void main() { foreach (mod; ModuleInfo) { foreach (c; mod.localClasses) { writeln(c); } } } ...output: modtemp.Foo core.exception.RangeError core.exception.AssertError etc... Neither 'Bar!int' nor 'BarInt' appear in 'localClasses'. Ideas?
Re: Testing whether static foreach is available
On Saturday, 9 September 2017 at 16:53:19 UTC, jmh530 wrote: On Saturday, 9 September 2017 at 16:30:51 UTC, Jean-Louis Leroy wrote: Also, is it possible to conditionally compile depending on the compiler's version, not only the compiler (I mean, not compile a block if it's GDC version 5.4.1 or lower)? What you really need is a version statement based on the version of the D language, not the version of DMD or LDC or GDC per se. Something like version(DLANGSEMVER >= 2.076.0) { //include static foreach code. } but we can't do conditionals in version blocks, so you'd need a static if. Alternately, we'd also need a trait or something to get the semver of the compiler. For some of my needs (like here https://github.com/jll63/openmethods.d/blob/v1.0.0-rc.2/source/openmethods.d#L1509) 'static if' would work. But I'd really like to provide a template mixin alternative to the string mixin I use in openmethods ('mixin(registerMethods)'). Hmmm...Generally speaking, the lack of [your suggestion] will slow down the adoption of new cool features like 'static foreach'.
Testing whether static foreach is available
Is there a way to test whether 'static foreach' is available, e.g. via a version symbol? Also, is it possible to conditionally compile depending on the compiler's version, not only the compiler (I mean, not compile a block if it's GDC version 5.4.1 or lower)? I did look at the docs, several times, couldn't find it...
Re: nested module problem
On Saturday, 2 September 2017 at 21:42:59 UTC, Moritz Maxeiner wrote: On Saturday, 2 September 2017 at 21:24:19 UTC, Jean-Louis Leroy wrote: [...] Yes, these now both fail because you cannot have a module `foo` and a package `foo` at the same time (they share a namespace), I forgot about that. [...] (same as before, no issue here) [...] You created the 'foo' package by specifying `module foo.bar` in foo/bar.d. [...] AFAIK you can't; consider: -- baz.d --- import foo; in the same directory as foo.d. If foo/package.d exists (with `module foo` inside), what should baz.d import? foo.d or foo/package.d? The point being that we could have either used foo/package.d or foo.d for a package file, but not both (as that would allow ambiguity) and package.d was chosen. [1] https://dlang.org/spec/module.html#package-module Hmmm I see...I was thinking of spinning the runtime part of my openmethods library into its own module (like here https://github.com/jll63/openmethods.d/tree/split-runtime/source/openmethods) but it looks like a bad idea...
Re: nested module problem
On Saturday, 2 September 2017 at 20:48:22 UTC, Moritz Maxeiner wrote: So the compiler wants you to import it by the name it has inferred for you (The fix being either specifying the module name in foo/bar.d as `module foo.bar`, or importing it as via `import bar;` in foo.d). [1] https://dlang.org/spec/module.html I thought of doing that, it merely changed the error. OK now I have: in foo.d: module foo; import foo.bar; in foo/bar.d: module foo.bar; $ dmd -c foo.d foo/bar.d foo/bar.d(1): Error: package name 'foo' conflicts with usage as a module name in file foo.d If I compile separately: jll@ORAC:~/dev/d/tests/modules$ dmd -I. -c foo.d foo/bar.d(1): Error: package name 'foo' conflicts with usage as a module name in file foo.d jll@ORAC:~/dev/d/tests/modules$ dmd -I. -c foo/bar.d It believes that 'foo' is a package...because there is a 'foo' directory? I see that a workaround is to move foo.d to foo/package.d but I would like to avoid that.
Re: Open Methods: From C++ to D
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.
nested module problem
So I have: jll@ORAC:~/dev/d/tests/modules$ tree . ├── foo │ └── bar.d └── foo.d foo.d contains: import foo.bar; bar.d is empty. Now I try compiling: jll@ORAC:~/dev/d/tests/modules$ dmd -c foo.d jll@ORAC:~/dev/d/tests/modules$ dmd -c foo/bar.d So far so good. Now I try it the way dub does it: jll@ORAC:~/dev/d/tests/modules$ dmd -c foo.d foo/bar.d foo.d(1): Error: module bar from file foo/bar.d must be imported with 'import bar;' What's up?
Re: Open Methods: From C++ to D
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?
Re: Open Methods: From C++ to D
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/b63a88132e639bb23bb7cb305f4457450f865c6a 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.
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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()).
Re: Article: Writing Julia style multiple dispatch code in D
On Thursday, 31 August 2017 at 06:58:53 UTC, Petar Kirov [ZombineDev] wrote: The workaround is to cast to Object before getting the typeid. The cause for this behavior is that if you have an interface reference to an object it points to the interface vtbl and not to the Object base class vtbl. Yeah I know. And in my openmethods lib I simply follow the pointers, without relying on typeid. It does look to me like a bug though. D has all the info it needs to implement the process you describe.
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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...
Re: Article: Writing Julia style multiple dispatch code in D
On Wednesday, 30 August 2017 at 22:30:12 UTC, data pulverizer wrote: On Wednesday, 30 August 2017 at 22:10:38 UTC, Jean-Louis Leroy wrote: On Wednesday, 30 August 2017 at 21:30:29 UTC, data pulverizer wrote: In the light of this I think your package just became more interesting to me. I think that your work and mine are complementary :-) Here is one strange difference between inheriting from an interface and a class: ``` interface Animal{} class Dog: Animal{} class Cat: Animal{} void main() { Animal[] x; x ~= new Cat(); x ~= new Dog(); x ~= new Cat(); writeln(typeid(x[0])); // Gives Animal } ``` But if Animal is set to a class the typeid gives Cat, why does this happen? Does this mean that inheriting from an interface is not really polymorphism? I noticed that too. Still scratching my head.
Re: Article: Writing Julia style multiple dispatch code in D
On Wednesday, 30 August 2017 at 21:30:29 UTC, data pulverizer wrote: In the light of this I think your package just became more interesting to me. I think that your work and mine are complementary :-)
Re: Article: Writing Julia style multiple dispatch code in D
On Wednesday, 30 August 2017 at 17:16:59 UTC, data pulverizer wrote: On Wednesday, 30 August 2017 at 17:14:37 UTC, data pulverizer wrote: On Wednesday, 30 August 2017 at 16:45:19 UTC, data pulverizer wrote: You mentioned Julia in your article, however for clarity I would point out that Julia doesn't have OOP-type polymorphism. There is no notion of being able to do something like: Animal snoopy = new Dog(); p.s. my bad, I was wrong about that! Turns out you can do something like this in Julia (apologies for the Julia code in a D forum): abstract type Animal end struct Dog <: Animal end struct Cat <: Animal end x = Array{Animal}(3) x[1] = Cat(); x[2] = Dog(); x[3] = Cat(); x # returns 3-element Array{Animal,1}: Cat() Dog() Cat() p.p.s typeof(x[1]) # returns Cat so it isn't really polymorphism - the object is never converted to the "parent" type! Lol ... sorry for the confusion! Which is polymorphism After mulling over this example, I don't see how this proves that Julia does *not* support run time polymorphism. On the contrary. If you translate this to D you get the same result by the way: import std.stdio; class Animal {} class Cat : Animal {} void main() { Animal[] array; array ~= new Cat(); writeln(typeid(array[0])); // typeid.Cat }
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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.
Re: Article: Writing Julia style multiple dispatch code in D
On Wednesday, 30 August 2017 at 17:16:59 UTC, data pulverizer wrote: p.p.s typeof(x[1]) # returns Cat so it isn't really polymorphism - the object is never converted to the "parent" type! Lol ... sorry for the confusion! Which is polymorphism Haha what I know of Julia is what wikipedia says. Confusing indeed...
Re: Article: Writing Julia style multiple dispatch code in D
On Wednesday, 30 August 2017 at 16:45:19 UTC, data pulverizer wrote: One thing that confused me was examples like this ... @method Matrix _plus(DiagonalMatrix a, DiagonalMatrix b) { // just add the elements on diagonals // return a DiagonalMatrix } Which is marked as returning a DiagonalMatrix rather than a Matrix by polymorphism however the function is marked Matrix return type. Indeed returning a DiagonalMatrix would work, and is marginally more useful (in case you want to call the specialization directly). I'll update the example. Thanks.
Re: Open Methods: From C++ to D
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...
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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.
Re: Open Methods: From C++ to D
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"; }
Re: Open Methods: From C++ to D
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
Re: Open Methods: From C++ to D
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?
Re: Article: Writing Julia style multiple dispatch code in D
On Thursday, 24 August 2017 at 23:50:21 UTC, data pulverizer wrote: I find OOP-polymorphic types ultimately unsatisfying, but I don't know of anyway to write, compile and load a D script with new types and methods on the fly into the same session. That is why binding membership and polymorphism together is a historical wrong turn. CLOS had it right but the world followed the Simula/Smalltalk path because of a nice metaphor (objects sending messages to each other). My openmethods library allows you to add methods "from outside" and also supports dynamic loading: you can add new methods to existing classes and new classes to hierarchies that have methods. See the blog post that just came up.
Re: Article: Writing Julia style multiple dispatch code in D
On Thursday, 24 August 2017 at 23:50:21 UTC, data pulverizer wrote: I find OOP-polymorphic types ultimately unsatisfying, but I don't know of anyway to write, compile and load a D script with new types and methods on the fly into the same session. That is why binding membership and polymorphism together is a historical wrong turn. CLOS had it right but the world followed the Simula/Smalltalk path because of a nice metaphor (objects sending messages to each other). My openmethods library allows you to add methods "from outside" and also supports dynamic loading: you can add new methods to existing classes and new classes to hierarchies that have methods. See the blog post that just came up.
Re: Mixin templates vs interface files
On Tuesday, 8 August 2017 at 01:04:30 UTC, Jean-Louis Leroy wrote: On Sunday, 6 August 2017 at 13:24:23 UTC, Jean-Louis Leroy wrote: Consider: // app.d [...] I see no reason why this() is kept and ~this() not. Should I report this as a bug? It seems to be happening here: https://github.com/dlang/dmd/blob/master/src/ddmd/hdrgen.d#L1982 Maybe if (hgs.hdrgen) return; should read: if (hgs.hdrgen && !hgs.tpltMember) return; When I make that change I get my static ~this in the .di file. Beyond that, I don't see the reason why visit(StaticDtorDeclaration d) is not a copy-paste of visit(StaticCtorDeclaration d) with one tilde added. PR?
Re: Mixin templates vs interface files
On Sunday, 6 August 2017 at 13:24:23 UTC, Jean-Louis Leroy wrote: Consider: // app.d [...] I see no reason why this() is kept and ~this() not. Should I report this as a bug?
Mixin templates vs interface files
Consider: // app.d import std.stdio; import tracemodule; mixin traceModule; void main() { writeln("main"); } // tracemodule.d module tracemodule; import std.stdio; mixin template traceModule(string moduleName = __MODULE__) { import std.stdio; static this() { writeln("init " ~ moduleName); } static ~this() { writeln("deinit " ~ moduleName); } } When I compile like this: $ rm -f *.o *.di $ dmd -c tracemodule.d $ dmd -c app.d $ dmd app.o tracemodule.o -of=app ...and run 'app' I get the expected output: $ ./app init app main deinit app Now if I throw -H in, things get weird: $ rm -f *.o *.di $ dmd -c -H tracemodule.d $ dmd -c app.d $ dmd app.o tracemodule.o -of=app $ ./app init app main Indeed when I look at the content of the interface file, I see: // D import file generated from 'tracemodule.d' module tracemodule; import std.stdio; template traceModule(string moduleName = __MODULE__) { import std.stdio; static this() { writeln("init " ~ moduleName); } } 'static this()' is there, but no 'static ~this()'. What's happening here?