Re: question about keeeping reference to toStringz()
On Thursday, 31 May 2018 at 01:12:34 UTC, Dr.No wrote: is foo() is being called from a thread, how I am supposed to keep cstring "alive"? As Jonathan explained, you don't have to worry about it if foo() itself doesn't assign the pointer to anything internally. That will be the case for most C functions. Well-behaved functions that need to keep the string around will copy it. That said, you need to be sure you understand fully what any C function you call is doing with the strings, or pointers to any memory allocated by the GC, that you pass to them. In the rare cases where the C function does keep the pointer and you do need to keep a reference (if you don't have one already), the simplest approach is this one: import core.memory; GC.addRoot(cstring); Then, when you no longer need it: GC.removeRoot(cstring); https://dlang.org/phobos/core_memory.html#.GC.addRoot
Re: question about keeeping reference to toStringz()
On Thursday, May 31, 2018 01:12:34 Dr.No via Digitalmars-d-learn wrote: > On Wednesday, 30 May 2018 at 20:43:48 UTC, Ali Çehreli wrote: > > On 05/30/2018 01:09 PM, Dr.No wrote: > > > consider a C function with this prototype: > > >> void foo(const char *baa); > > > > > > Does it means I should do: > > >> string s = ...; > > >> auto cstring = s.toStringz; > > >> foo(cstring); > > > > > > rather just: > > >> foo(s.toStringz); > > > > > > ? > > > > It depends. cstring method above is not sufficient if cstring's > > life is shorter than the C library's use: > > > > void bar() { > > > > string s = ...; > > auto cstring = s.toStringz; > > foo(cstring); > > > > } // <- cstring is gone > > > > What if the library saved that pointer while performing foo()? > > > > If cstring is in module-scope or in a container (e.g. an array) > > that's in module-scope then it's fine. But then, you would have > > to remove it from that container when the C library does not > > need that pointer anymore. > > > > Ali > > is foo() is being called from a thread, how I am supposed to keep > cstring "alive"? If it's being passed to foo, then it should be on the stack until foo returns, in which case, the GC should see it when it scans. It's when foo could keep a reference to the pointer that you have a problem, since then as soon as foo returns, the pointer you passed to foo won't be on the stack anymore. So, in that case, you'd have to store the pointer somewhere in D code so that the GC will see it when scanning. Or are you concerned about something like spinning up a thread, calling foo, and then exiting the thread while foo stores the pointer somewhere? If that's the case, then you'll need to store the pointer in a shared or __gshared variable in D code so that you can still refer to it after the thread terminates. - Jonathan M Davis
Re: What's the purpose of the 'in' keyword ?
On Wednesday, May 30, 2018 22:16:28 aberba via Digitalmars-d-learn wrote: > On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: > > On Sunday, May 27, 2018 16:28:56 Russel Winder via > > > > Digitalmars-d-learn wrote: > >> On Sun, 2018-05-27 at 13:10 +, Adam D. Ruppe via > >> Digitalmars-d-learn > > > > - Jonathan M Davis > > Jonathan, which font were you using in your DConf powerpoint > presentation for source code? It made the code look really > nice... I'd point you to my reply to Ali, since what he figured out will probably tell you better than I could. > and also you have good naming skills. Thanks. I'm glad that someone thinks so. Naming is pretty much the king of bikeshedding in programming, and I've been in far too many arguments on that topic before. Far too often, it seems like no matter what you name something, someone is going to think that the name is terrible. - Jonathan M Davis
Re: question about keeeping reference to toStringz()
On Wednesday, 30 May 2018 at 20:43:48 UTC, Ali Çehreli wrote: On 05/30/2018 01:09 PM, Dr.No wrote: > consider a C function with this prototype: >> void foo(const char *baa); > > Does it means I should do: > >> string s = ...; >> auto cstring = s.toStringz; >> foo(cstring); > > rather just: > >> foo(s.toStringz); > > ? It depends. cstring method above is not sufficient if cstring's life is shorter than the C library's use: void bar() { string s = ...; auto cstring = s.toStringz; foo(cstring); } // <- cstring is gone What if the library saved that pointer while performing foo()? If cstring is in module-scope or in a container (e.g. an array) that's in module-scope then it's fine. But then, you would have to remove it from that container when the C library does not need that pointer anymore. Ali is foo() is being called from a thread, how I am supposed to keep cstring "alive"?
Re: What's the purpose of the 'in' keyword ?
On Wednesday, May 30, 2018 15:28:53 Ali Çehreli via Digitalmars-d-learn wrote: > On 05/30/2018 03:16 PM, aberba wrote: > > On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: > >> On Sunday, May 27, 2018 16:28:56 Russel Winder via Digitalmars-d-learn > >> > >> wrote: > >>> On Sun, 2018-05-27 at 13:10 +, Adam D. Ruppe via > >>> Digitalmars-d-learn > >> > >> - Jonathan M Davis > > > > Jonathan, which font were you using in your DConf powerpoint > > presentation for source code? It made the code look really nice...and > > also you have good naming skills. > > The pdf file has that information in it: > >http://www.identifont.com/similar?76H Well, that's cool - especially since properly telling someone what the font was is kind of hard anyway, since I used latex to generate the slides, and you don't normally select a font directly with latex (rather, normally, you select a font family). I used the beamer package to generate the slides and the listings package for the code blocks. The code blocks were then configured to use \ttfamily for the font, so it's whatever gets selected for the ttfamily family of fonts. - Jonathan M Davis
Re: Constructing text with astericks
On Wednesday, 30 May 2018 at 22:57:06 UTC, aberba wrote: How will you approach this problem in D idiomatically? Well, I never bother with "idiomatically", so I can't speak to that, but a simple solution that would work is to realize that what you're basically asking for here is a bitmap. Each letter in your "font" would be a little bitmap that you copy into a destination buffer - itself a larger bitmap. Then, when it is complete, you can draw the destination buffer line by line to the screen. The data for your font may just be a bunch of string arrays in source, or an actual bitmap file you create outside the program and load at runtime or something like that. Just remember that you can't just `buffer ~= letter` - you need to do line by line since the two bitmaps will have different sizes.
Re: Constructing text with astericks
On Wednesday, 30 May 2018 at 22:57:06 UTC, aberba wrote: I've been given a challenge to write texts using asterisks to form the letters. D happen to have an unlimited amount of idioms yet i'm out out ideas as to the simplest approach. Task is to basically take a piece of text and write them as asterisks to the console. * * * * * * * * * * First solution I found was to create a class for each letter...like new A(), new B() and implement the logic withing each class. This doesn't scale and i'll have to write about 24 or more classes. Another complex but "makes sense" solution will be to use a GRID system like old digital watches but i'll need a more complex grid to draw complex letters using a dictionary of REPOPULATED indexes of asterisk for each word. First use the length of the string to compute the grid size and iterate over each character to indentify the dictionary of a letter's indexes to use: * *** ** ** *** ** *** ** *** (an R using a more complex Grid) How will you approach this problem in D idiomatically? I'd use an ascii art approach: - Programatically make bitmaps with each letter rendered using a monospaced font. - use higher order functions to make 2d arrays of ' ' and '*'
Re: Move and CTFE
On Wednesday, May 30, 2018 22:42:13 Q. Schroll via Digitalmars-d-learn wrote: > On Wednesday, 30 May 2018 at 21:02:07 UTC, Jonathan M Davis wrote: > > On Wednesday, May 30, 2018 20:42:38 Q. Schroll via > > > > Digitalmars-d-learn wrote: > >> It seems one cannot std.algorithm.mutation.move objects > >> explicitly. Say I have a non-copyable type > >> [...] > >> It fails because move() cannot be executed at compile time. The > >> reason > >> > >> "memcpy cannot be interpreted at compile time, because it > >> > >> has > >> no available source code" > >> sounds very suspicious. > > > > Why is it suspicious? memcpy is a C function, and you can't > > call C functions during CTFE precisely because the compiler > > doesn't have their source code. You can't call D functions > > either if the compiler doesn't have their source (e.g. if > > you're using a .di file to hide the implementation). > > I definitely do understand the error message and it makes sense > that it fails the way it's implemented. However, it makes no > sense that moving as a concept can fail at CTFE. That's what I > find suspicious. [Maybe 'suspicious' isn't the right term; I > couldn't express it better.] You can move rvalues at CTFE which > proves that the compiler can do it. > > >> Shouldn't it be possible to move at CTFE, > >> too, or does it mean, non-copyable types are practically > >> unusable > >> for CTFE? > > > > You can't do much in the way of pointer or memory manipulation > > during CTFE (e.g. no pointer arithmetic or reinterpret casts). > > So, I don't see how a move could be done during CTFE. Even if > > the source for memcpy were available during CTFE, I suspect > > that it wouldn't be allowed due to the lower level stuff that > > it does. > > That's the explanation why probably all currently possible > library alternatives to memcpy would fail. I suspected that when > encountering the error, but still wonder why memcpy or other > low-level stuff is even necessary to accomplish something the > compiler is perfectly able to do. > > From what I see, the reason for the hack is lack of > expressiveness: We don't have rvalue-refs in D (which I find > good) so, currently, there is no cast-solution as in C++. So for > a proper move() that works at CTFE, we'd need some specific tool. > > I have no idea of the details on how the compiler handles > lvalues. Would it make sense to add a compiler trait, > specifically to solve moving? Like __traits(move, > lvalue_expression) [name up for discussion] that is identical to > lvalue_expression with the exception that the (lvalue/rvalue) > flag (or whatever it is) is set to "rvalue". Basically, it's the > C++ solution: After the "cast", the compiler will proceed and > pretend it is an rvalue and therefore initiate moving. > > Do you think adding a trait to make move() and swap() work at > CTFE is worth it? > > A quick search showed me the class "Expression" has "virtual bool > isLvalue();" so it might be easy as wrapping and hooking that > virtual method. To me, [1] highly suggests that it works. > > [1] > https://github.com/dlang/dmd/blob/master/src/dmd/expression.d#L1219 I'm not sure that it really makes sense to worry about fixing stuff like this in CTFE before newCTFE is actually merged. For instance, as I understand it, current CTFE can't even really handle mutation. Rather, it creates a new value every time you mutate a variable. Don explained to me at one point about how even incrementing a variable allocates memory so that you then have a new value to use. Stuff like that is why CTFE is so slow and eats up so much memory. Much as it acts like it's running your code in a normal fashion, it's really not implemented that way (the reason that it works the way does having to do with how it grew into existence out of other features rather than being designed up front). The current CTFE implementation is incredibly hacky, and it's arguably a miracle that it can do as much as it can. newCTFE is taking a very different approach to CTFE, and in theory, it will fix many of the problems that CTFE currently has, but it's taking Stefan quite a while to get it to where it needs to be to actually merge it. - Jonathan M Davis
Constructing text with astericks
I've been given a challenge to write texts using asterisks to form the letters. D happen to have an unlimited amount of idioms yet i'm out out ideas as to the simplest approach. Task is to basically take a piece of text and write them as asterisks to the console. * * * * * * * * * * First solution I found was to create a class for each letter...like new A(), new B() and implement the logic withing each class. This doesn't scale and i'll have to write about 24 or more classes. Another complex but "makes sense" solution will be to use a GRID system like old digital watches but i'll need a more complex grid to draw complex letters using a dictionary of REPOPULATED indexes of asterisk for each word. First use the length of the string to compute the grid size and iterate over each character to indentify the dictionary of a letter's indexes to use: * *** ** ** *** ** *** ** *** (an R using a more complex Grid) How will you approach this problem in D idiomatically?
Re: Move and CTFE
On Wednesday, 30 May 2018 at 21:02:07 UTC, Jonathan M Davis wrote: On Wednesday, May 30, 2018 20:42:38 Q. Schroll via Digitalmars-d-learn wrote: It seems one cannot std.algorithm.mutation.move objects explicitly. Say I have a non-copyable type [...] It fails because move() cannot be executed at compile time. The reason "memcpy cannot be interpreted at compile time, because it has no available source code" sounds very suspicious. Why is it suspicious? memcpy is a C function, and you can't call C functions during CTFE precisely because the compiler doesn't have their source code. You can't call D functions either if the compiler doesn't have their source (e.g. if you're using a .di file to hide the implementation). I definitely do understand the error message and it makes sense that it fails the way it's implemented. However, it makes no sense that moving as a concept can fail at CTFE. That's what I find suspicious. [Maybe 'suspicious' isn't the right term; I couldn't express it better.] You can move rvalues at CTFE which proves that the compiler can do it. Shouldn't it be possible to move at CTFE, too, or does it mean, non-copyable types are practically unusable for CTFE? You can't do much in the way of pointer or memory manipulation during CTFE (e.g. no pointer arithmetic or reinterpret casts). So, I don't see how a move could be done during CTFE. Even if the source for memcpy were available during CTFE, I suspect that it wouldn't be allowed due to the lower level stuff that it does. That's the explanation why probably all currently possible library alternatives to memcpy would fail. I suspected that when encountering the error, but still wonder why memcpy or other low-level stuff is even necessary to accomplish something the compiler is perfectly able to do. From what I see, the reason for the hack is lack of expressiveness: We don't have rvalue-refs in D (which I find good) so, currently, there is no cast-solution as in C++. So for a proper move() that works at CTFE, we'd need some specific tool. I have no idea of the details on how the compiler handles lvalues. Would it make sense to add a compiler trait, specifically to solve moving? Like __traits(move, lvalue_expression) [name up for discussion] that is identical to lvalue_expression with the exception that the (lvalue/rvalue) flag (or whatever it is) is set to "rvalue". Basically, it's the C++ solution: After the "cast", the compiler will proceed and pretend it is an rvalue and therefore initiate moving. Do you think adding a trait to make move() and swap() work at CTFE is worth it? A quick search showed me the class "Expression" has "virtual bool isLvalue();" so it might be easy as wrapping and hooking that virtual method. To me, [1] highly suggests that it works. [1] https://github.com/dlang/dmd/blob/master/src/dmd/expression.d#L1219
Re: What's the purpose of the 'in' keyword ?
On 05/30/2018 03:16 PM, aberba wrote: On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: On Sunday, May 27, 2018 16:28:56 Russel Winder via Digitalmars-d-learn wrote: On Sun, 2018-05-27 at 13:10 +, Adam D. Ruppe via Digitalmars-d-learn - Jonathan M Davis Jonathan, which font were you using in your DConf powerpoint presentation for source code? It made the code look really nice...and also you have good naming skills. The pdf file has that information in it: http://www.identifont.com/similar?76H Ali
Re: What's the purpose of the 'in' keyword ?
On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: On Sunday, May 27, 2018 16:28:56 Russel Winder via Digitalmars-d-learn wrote: On Sun, 2018-05-27 at 13:10 +, Adam D. Ruppe via Digitalmars-d-learn - Jonathan M Davis Jonathan, which font were you using in your DConf powerpoint presentation for source code? It made the code look really nice...and also you have good naming skills.
Re: Setter chaining
The above idea can be emulated in code, abiet ugly and useless: https://dpaste.dzfl.pl/bd118bc1910c import std.stdio; struct CT(A,B) { A v; B t; alias v this; B opUnary(string s)() if (s == "~") { return t; } A opUnary(string s)() if (s == "*") { return v; } } class C { int q; CT!(int, typeof(this)) foo() { q = 3; CT!(int, typeof(this)) v; v.t = this; v.v = q; return v; } CT!(int, typeof(this)) bar(int y) { q = q + y; CT!(int, typeof(this)) v; v.t = this; v.v = q; return v; } } void main() { C c = new C(); auto x = *((~c.foo()).bar(6)); writeln(x); } With a language implementation, all one would need is a symbol, using #, everything would simplify to class C { int q; int foo() { q = 3; return q; } int bar(int y) { q = q + y; return q;} } auto x = c.#foo().bar(6);
Re: no [] operator overload for type Chunks!(char[])
On Wednesday, 30 May 2018 at 21:27:44 UTC, Ali Çehreli wrote: On 05/30/2018 02:19 PM, Malte wrote: Why does this code complain at the last line about a missing [] operator overload? auto buffer = new char[6]; auto chunked = buffer.chunks(3); chunked[1][2] = '!'; Same happens with wchar. Dchar and byte work as expected. UTF-8 auto decoding strikes again. :) Even though the original container is char[], passing it through Phobos algorithms generated range of dchar. The thing is, those dchar elements are generated (decoded from chars) "on the fly" as one iterates over the range. Which means, there is no array of dchar to speak of, so there is no random access. Ali I see. Not what I would have expected, but makes sense for people working with UTF-8 strings. Thanks for the fast answer.
Re: no [] operator overload for type Chunks!(char[])
On 05/30/2018 02:19 PM, Malte wrote: Why does this code complain at the last line about a missing [] operator overload? auto buffer = new char[6]; auto chunked = buffer.chunks(3); chunked[1][2] = '!'; Same happens with wchar. Dchar and byte work as expected. UTF-8 auto decoding strikes again. :) Even though the original container is char[], passing it through Phobos algorithms generated range of dchar. The thing is, those dchar elements are generated (decoded from chars) "on the fly" as one iterates over the range. Which means, there is no array of dchar to speak of, so there is no random access. Ali
no [] operator overload for type Chunks!(char[])
Why does this code complain at the last line about a missing [] operator overload? auto buffer = new char[6]; auto chunked = buffer.chunks(3); chunked[1][2] = '!'; Same happens with wchar. Dchar and byte work as expected.
Re: Move and CTFE
On Wednesday, May 30, 2018 20:42:38 Q. Schroll via Digitalmars-d-learn wrote: > It seems one cannot std.algorithm.mutation.move objects > explicitly. Say I have a non-copyable type > > struct NoCopy > { > int payload; // some payload > pure nothrow @nogc @safe @disable: > this(this); // make it non copyable > } > > that is being used in a compile-time function evaluation where > values are being moved. > > int f() pure nothrow @nogc @safe > { > import std.algorithm.mutation : move; > NoCopy nc = NoCopy(1), nc2 = NoCopy(3); > nc = move(nc2); > return 0; > } > > static assert(f() == 0); // trigger CTFE > > It fails because move() cannot be executed at compile time. The > reason > "memcpy cannot be interpreted at compile time, because it has > no available source code" > sounds very suspicious. Why is it suspicious? memcpy is a C function, and you can't call C functions during CTFE precisely because the compiler doesn't have their source code. You can't call D functions either if the compiler doesn't have their source (e.g. if you're using a .di file to hide the implementation). > Shouldn't it be possible to move at CTFE, > too, or does it mean, non-copyable types are practically unusable > for CTFE? You can't do much in the way of pointer or memory manipulation during CTFE (e.g. no pointer arithmetic or reinterpret casts). So, I don't see how a move could be done during CTFE. Even if the source for memcpy were available during CTFE, I suspect that it wouldn't be allowed due to the lower level stuff that it does. Maybe the newCTFE stuff that Stefan is working on can do more in this area (I don't know), but in general, anything that's at all low-level is forbidden in CTFE. - Jonathan M Davis
Re: Setter chaining
On Wednesday, 30 May 2018 at 15:46:36 UTC, Steven Schveighoffer wrote: On 5/30/18 10:49 AM, DigitalDesigns wrote: Does it sound good? class X { double x; @property X foo(double y) { x = y; return this; } @property X bar(double y) { x = y + 5; return this; } } void main() { X x = new X(); x.foo(3).bar(4); } It sort of emulates UFCS but I'm not sure if it's more trouble than it's worth. I figure it would be better than just returning void as it provides the option to chain but not sure if it will come back to bite me. Yes, I do this kind of stuff, but you need to word your functions correctly. I would avoid @property there, as this implies you should use it like: x.foo = 5; and if you return a reference to the type itself, it will read weird if you do it that way: auto five = (x.foo = 5); Here the name of the function is really really important. In my use case, I am kind of using it in an SQL builder type, where each time you call a method it adds some piece of the query. Like: auto query = table.select("id, name").where("foo = 5").orderBy("name"); -Steve Well, what I mean is to be able to have the ability to assign like a field or a function. sometimes I might want to use it as a property like x.foo = 5; and sometimes like a method x.foo(5).foo(8); for chaining. Rather than having to to create setfoo and such. Since D allows both syntaxes to be used, rather than returning void, turning parenting object allows the chaining to take place. Since the trick here is to be consistent, all setters must follow this principle, it shouldn't be a problem with consistency. auto five = (x.foo = 5); I wouldn't do that,just doesn't look right but I see your point. What would be cool is if D had some special way to return the object of the class the setter was in. auto x = (@x.foo = 5); Here @ returns x but first computes x.foo = 5;. In a way, it is like "this". @ gets the "this" of the function. Could work on any function: class Y { void foo(); @property int baz(); @property double bar(int x); } y.@foo() returns y; y.@baz() returns y; y.@bar(3) returns y; Essentially one could few all functions as returning this and the value in a tuple and be default the value is returned and using a "selector" character will return this. class Y { Tuple!(void, typeof(this)) foo(); Tuple!(int, typeof(this)) baz(); Tuple!(double, typeof(this)) bar(int x); } y.foo()[1] returns y; ... The compiler could simplify all this and by putting this in a register it could be be quite fast. In fact, since these are member functions and this is passed it will just fall through so very little overhead. The compiler can also optimize the code. Might take a bit to verify all the corner cases but would probably be useful once people could use it and get used to it. @, $, |, ?, ! or many symbols could be used without ambiguity because a dot will always preceded them.
Move and CTFE
It seems one cannot std.algorithm.mutation.move objects explicitly. Say I have a non-copyable type struct NoCopy { int payload; // some payload pure nothrow @nogc @safe @disable: this(this); // make it non copyable } that is being used in a compile-time function evaluation where values are being moved. int f() pure nothrow @nogc @safe { import std.algorithm.mutation : move; NoCopy nc = NoCopy(1), nc2 = NoCopy(3); nc = move(nc2); return 0; } static assert(f() == 0); // trigger CTFE It fails because move() cannot be executed at compile time. The reason "memcpy cannot be interpreted at compile time, because it has no available source code" sounds very suspicious. Shouldn't it be possible to move at CTFE, too, or does it mean, non-copyable types are practically unusable for CTFE?
Re: question about keeeping reference to toStringz()
On 05/30/2018 01:09 PM, Dr.No wrote: > consider a C function with this prototype: >> void foo(const char *baa); > > Does it means I should do: > >> string s = ...; >> auto cstring = s.toStringz; >> foo(cstring); > > rather just: > >> foo(s.toStringz); > > ? It depends. cstring method above is not sufficient if cstring's life is shorter than the C library's use: void bar() { string s = ...; auto cstring = s.toStringz; foo(cstring); } // <- cstring is gone What if the library saved that pointer while performing foo()? If cstring is in module-scope or in a container (e.g. an array) that's in module-scope then it's fine. But then, you would have to remove it from that container when the C library does not need that pointer anymore. Ali
question about keeeping reference to toStringz()
The documentation says: Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it. (from https://dlang.org/library/std/string/to_stringz.html) consider a C function with this prototype: void foo(const char *baa); Does it means I should do: string s = ...; auto cstring = s.toStringz; foo(cstring); rather just: foo(s.toStringz); ?
Re: Setter chaining
On 5/30/18 10:49 AM, DigitalDesigns wrote: Does it sound good? class X { double x; @property X foo(double y) { x = y; return this; } @property X bar(double y) { x = y + 5; return this; } } void main() { X x = new X(); x.foo(3).bar(4); } It sort of emulates UFCS but I'm not sure if it's more trouble than it's worth. I figure it would be better than just returning void as it provides the option to chain but not sure if it will come back to bite me. Yes, I do this kind of stuff, but you need to word your functions correctly. I would avoid @property there, as this implies you should use it like: x.foo = 5; and if you return a reference to the type itself, it will read weird if you do it that way: auto five = (x.foo = 5); Here the name of the function is really really important. In my use case, I am kind of using it in an SQL builder type, where each time you call a method it adds some piece of the query. Like: auto query = table.select("id, name").where("foo = 5").orderBy("name"); -Steve
Re: What's the purpose of the 'in' keyword ?
On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: [...] Honestly, I'd suggest that folks never use in at this point. There's zero benefit to it. [...] Exactly. If you intend const, just write const. If you intend const scope, write const scope.
Setter chaining
Does it sound good? class X { double x; @property X foo(double y) { x = y; return this; } @property X bar(double y) { x = y + 5; return this; } } void main() { X x = new X(); x.foo(3).bar(4); } It sort of emulates UFCS but I'm not sure if it's more trouble than it's worth. I figure it would be better than just returning void as it provides the option to chain but not sure if it will come back to bite me.
Re: Build interface from abstract class
On Wednesday, 30 May 2018 at 10:31:27 UTC, Simen Kjærås wrote: On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote: I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means. 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again. 2. Your method of function creation does not pick up attributes and other factors so it is weak. Here is my solution that does not solve problem 2: [Neat stuff] Neat, but as you say it doesn't handle attributes or UDAs. The use of stringof is also a red flag - the same name can apply to different types in different scopes, and aliases may confuse it. Here's a version that solves both of those issues: import std.array : join; import std.meta : ApplyLeft, staticMap, Filter, Alias; import std.traits; enum isPublic(alias overload) = Alias!(__traits(getProtection, overload) == "public"); interface InterfaceFromClass(T, alias filter = isPublic) { static foreach (overload; Filter!(filter, staticMap!(ApplyLeft!(MemberFunctionsTuple, T), __traits(derivedMembers, T mixin("@(__traits(getAttributes, overload)) "~attributes!overload~" ReturnType!overload "~__traits(identifier, overload)~"(Parameters!overload);"); } string attributes(alias overload)() { enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, overload), "pure", "nothrow", "ref", "@property", "@trusted", "@safe", "@nogc", "@system", "const", "immutable", "inout", "shared", "return", "scope"); return [attrs].join(" "); } alias A = InterfaceFromClass!C; abstract class C : A { int n; @("InterfaceMembers") { @(3) ref int foo(ref int a) { return n; } @(19) @safe void bar() { } } } // https://issues.dlang.org/show_bug.cgi?id=18915 // class D : C {} static assert([__traits(allMembers, A)] == ["foo", "bar"]); static assert(functionAttributes!(A.foo) == functionAttributes!(C.foo)); static assert(functionAttributes!(A.bar) == functionAttributes!(C.bar)); static assert(is(Parameters!(A.foo) == Parameters!(C.foo))); static assert(is(Parameters!(A.bar) == Parameters!(C.bar))); Note the link to issue 18915 (that's your 'string mixin output works...' post). I believe if we can fix that, the above should work. -- Simen Yeah! with a little work you can include fields in the interfacemembers because they will be ignored. I see no reason to have to declare an interface in D except in rare occasions! One should be able to abstract out an interface from a class or abstract class and use it as the base only for others to use. If a program was "sealed" there would be no real point in using interfaces(assuming it was designed to perfection) except to get around the diamond problem, which is what interfaces solve but in the process have forced us to duplicate code. The above technique alleviates that problem greatly. It's still bring the members inside the interface because it allows one to add final, static, and normal members if desired, although, this can be done by using another interface and inheriting from that.
Re: Build interface from abstract class
On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote: I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means. 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again. 2. Your method of function creation does not pick up attributes and other factors so it is weak. Here is my solution that does not solve problem 2: [Neat stuff] Neat, but as you say it doesn't handle attributes or UDAs. The use of stringof is also a red flag - the same name can apply to different types in different scopes, and aliases may confuse it. Here's a version that solves both of those issues: import std.array : join; import std.meta : ApplyLeft, staticMap, Filter, Alias; import std.traits; enum isPublic(alias overload) = Alias!(__traits(getProtection, overload) == "public"); interface InterfaceFromClass(T, alias filter = isPublic) { static foreach (overload; Filter!(filter, staticMap!(ApplyLeft!(MemberFunctionsTuple, T), __traits(derivedMembers, T mixin("@(__traits(getAttributes, overload)) "~attributes!overload~" ReturnType!overload "~__traits(identifier, overload)~"(Parameters!overload);"); } string attributes(alias overload)() { enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, overload), "pure", "nothrow", "ref", "@property", "@trusted", "@safe", "@nogc", "@system", "const", "immutable", "inout", "shared", "return", "scope"); return [attrs].join(" "); } alias A = InterfaceFromClass!C; abstract class C : A { int n; @("InterfaceMembers") { @(3) ref int foo(ref int a) { return n; } @(19) @safe void bar() { } } } // https://issues.dlang.org/show_bug.cgi?id=18915 // class D : C {} static assert([__traits(allMembers, A)] == ["foo", "bar"]); static assert(functionAttributes!(A.foo) == functionAttributes!(C.foo)); static assert(functionAttributes!(A.bar) == functionAttributes!(C.bar)); static assert(is(Parameters!(A.foo) == Parameters!(C.foo))); static assert(is(Parameters!(A.bar) == Parameters!(C.bar))); Note the link to issue 18915 (that's your 'string mixin output works...' post). I believe if we can fix that, the above should work. -- Simen
Re: Logging inside struct?
On Wednesday, 30 May 2018 at 10:07:35 UTC, Simen Kjærås wrote: On Wednesday, 30 May 2018 at 09:58:16 UTC, biocyberman wrote: [...] This line: writeln("got num: %s, of type: %s", num, typeof(num)); [...] Problem solved. Thanks Simen!
Re: Logging inside struct?
On Wednesday, 30 May 2018 at 09:58:16 UTC, biocyberman wrote: How do I add logging for this struct? https://run.dlang.io/is/9N6N4o If not possible, what's the alternative? This line: writeln("got num: %s, of type: %s", num, typeof(num)); Gives this error message: onlineapp.d(7): Error: cannot pass type int as a function argument The error message says exactly what's wrong - you can't pass a type as a runtime argument. You can get a string representation using .stringof: writeln("got num: %s, of type: %s", num, typeof(num).stringof); Next up: if prints this: got num: %s, of type: %s1int 1 You probably want something more like this: got num: 1, of type: int 1 The problem is you're using writeln, which only dumps its arguments to stdout in the order they're passed. writefln does formatting using %s: writefln("got num: %s, of type: %s", num, typeof(num).stringof); -- Simen
Logging inside struct?
How do I add logging for this struct? https://run.dlang.io/is/9N6N4o If not possible, what's the alternative?
Re: CMake support for D
On Tuesday, 27 February 2018 at 14:32:54 UTC, King_DuckZ wrote: ... My problem is mixing D with C and C++ ... you found already Dragos cmake-d, but not sure if you also know Dragos talk about mixing D with C/C++. If not, have a look: https://gitlab.com/dcarp/MUCplusplus/tree/master/2016.01.28
Re: string mixin output works when directly used but when generator is used D fails
On Tuesday, 29 May 2018 at 21:19:01 UTC, DigitalDesigns wrote: https://dpaste.dzfl.pl/67691db19ce8 Simplified: interface A { import std.meta : AliasSeq; alias a = AliasSeq!(__traits(getMember, B, "foo")); void foo(); } class B : A { void foo() { } } It seems the compiler is looking at the class before the interface is ready, and that the method thus isn't marked as implementing an interface method. Filed as https://issues.dlang.org/show_bug.cgi?id=18915 -- Simen
Re: CMake support for D
On Tuesday, 27 February 2018 at 14:32:54 UTC, King_DuckZ wrote: On Tuesday, 27 February 2018 at 09:20:21 UTC, Russel Winder wrote: [...] Right, I stand corrected about Rust, though as you say there are those who use it with CMake. About cmake-d, there's this https://github.com/dcarp/cmake-d/issues/19, which I could work around. More seriously though, it doesn't track dependencies between .d files. So if for example you have: [...] Are there any news at all about CMake support? Should I just give up?