Template shenannigans with multiple datatypes
I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. This all works fine if you have a single template type. But what if I want ... multiple graphs? I cannot do D class intrinsicGraph(T???) { (void*) dataSources[]; } and have it become whatever datatype I want. Even if I'm always storing the values in a float buffer, the dataSources themselves cannot be multiple types. Basically I'm wondering if there's a way to have D int FPS; float frameTime; // graph myGraph; myGraph.add(&frameTime); myGraph.add(&fps); and it enumerates through its dataSources array and adds to the relevant buffers. There is a key that might help, they're all types that can resolve to integer or float. I'm not trying to add support for adding myRandomClass or networkPacket. Only things that can resolve down to float in some form. Is there some kind of clue in having an array of Object (the fundamental superclass?)? I don't think this is necessarily a "run time" reflection problem. Because I could make a graph at compile time, and know its of type, say, (T V U). Say, float, double, uint. Some sort of vardiac template. But then how would you store that, unless you use some sort of mixins to write separate variables. (float\* dataSource0 and double\* dataSource1) Or, wrap each pointer in some sort of fat pointer class that stores the type and a void*, and have an array of those fat pointers and and use some compile time voodoo to cast back cast(float)dataSource[0] (zero is always float), cast(uint)dataSource[2] (index 2 has cast(uint) put in). Additional questions: This may sound strange but is there a way to avoid having to specify the template type twice? ```D instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = new intrinsic_graph!float(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = new intrinsic_graph!ulong(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ``` It'd be nice if I only had to specify the type once. It'd also be kinda nice if I could hide the fact I need to specify the type at all and have it automatically become whatever type the passed in value is: D instrinsicGraph testGraph(g.stats.fps) //automatically stores an integer buffer.
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On 13/05/2022 6:23 PM, MichaelBi wrote: render!("index.dt", showData()); There ya go, template arguments are run at compile time.
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On Friday, 13 May 2022 at 06:12:01 UTC, rikki cattermole wrote: Okay that is fine, now we need to see where showData is being called. thanks, here's the code: import vibe.vibe; import std.process; import std.conv : to; void main() { auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["0.0.0.0"]; readOption("port|p", &settings.port, "Sets the port used for serving HTTP."); readOption("bind-address|bind", &settings.bindAddresses[0], "Sets the address used for serving HTTP."); auto router = new URLRouter; router.get("*", serveStaticFiles("public/")); router.registerWebInterface(new ContentController); auto listener = listenHTTP(settings, router); scope (exit) { listener.stopListening(); } runApplication(); } class ContentController { void index() { render!("index.dt", showData()); } } struct Camera{ @name("_id") BsonObjectID id; // represented as "_id" in the database string brand; string model; } Camera[] showData(){ auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); MongoCollection cameras = eqpdb["cameras"]; Camera[] cs; auto results = cameras.find(); foreach(rec;results) cs ~= deserializeBson!Camera(rec); return cs; }
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
Okay that is fine, now we need to see where showData is being called.
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On Friday, 13 May 2022 at 06:01:29 UTC, rikki cattermole wrote: On 13/05/2022 5:52 PM, MichaelBi wrote: struct Camera{ @name("_id") BsonObjectID id; // represented as "_id" in the database string brand; string model; } the structure is mapping of database field structure. how to resolve? That code isn't the cause of your issue (its fine, no CTFE needed). We would need see more of your code surrounding: auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); here is the code: Camera[] showData(){ auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); MongoCollection cameras = eqpdb["cameras"]; Camera[] cs; auto results = cameras.find(); foreach(rec;results) cs ~= deserializeBson!Camera(rec); return cs; }
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On 13/05/2022 5:52 PM, MichaelBi wrote: struct Camera{ @name("_id") BsonObjectID id; // represented as "_id" in the database string brand; string model; } the structure is mapping of database field structure. how to resolve? That code isn't the cause of your issue (its fine, no CTFE needed). We would need see more of your code surrounding: auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku");
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On Friday, 13 May 2022 at 05:41:33 UTC, rikki cattermole wrote: On 13/05/2022 5:18 PM, MichaelBi wrote: i have code here: auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); the "MONGODB_URI" showed above already put into heroku's app config as the 'key' and there is a paired 'value'. so the uri is to extract the value which is to use for app to establish mongodb connection. and above code with error msg here: Error: `getenv` cannot be interpreted at compile time, because it has no available source code That part of the code is probably fine. Basically you have to be careful that: auto uri = environment.get("MONGODB_URI"); Isn't being executed during compilation. Stuff that typically cause this is anything that initializes a variable. Globals: shared Foo foo = Foo(...); Class fields: class Foo { Bar bar = Bar(...); } yes, then should be this? struct Camera{ @name("_id") BsonObjectID id; // represented as "_id" in the database string brand; string model; } the structure is mapping of database field structure. how to resolve?
Re: Help, in vibe.d, how to get configure var of mongodb in heroku?
On 13/05/2022 5:18 PM, MichaelBi wrote: i have code here: auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); the "MONGODB_URI" showed above already put into heroku's app config as the 'key' and there is a paired 'value'. so the uri is to extract the value which is to use for app to establish mongodb connection. and above code with error msg here: Error: `getenv` cannot be interpreted at compile time, because it has no available source code That part of the code is probably fine. Basically you have to be careful that: auto uri = environment.get("MONGODB_URI"); Isn't being executed during compilation. Stuff that typically cause this is anything that initializes a variable. Globals: shared Foo foo = Foo(...); Class fields: class Foo { Bar bar = Bar(...); }
Help, in vibe.d, how to get configure var of mongodb in heroku?
there are online documents of heroku on how to access config var value from code, and several code samples without D. link here: https://devcenter.heroku.com/articles/config-vars#accessing-config-var-values-from-code. i have code here: auto uri = environment.get("MONGODB_URI"); MongoClient conn = connectMongoDB(uri); MongoDatabase eqpdb = conn.getDatabase("MbEqpHeroku"); the "MONGODB_URI" showed above already put into heroku's app config as the 'key' and there is a paired 'value'. so the uri is to extract the value which is to use for app to establish mongodb connection. and above code with error msg here: Error: `getenv` cannot be interpreted at compile time, because it has no available source code so don't know how to make change. thanks in advance!
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 04:39:46 UTC, Tejas wrote: On Friday, 13 May 2022 at 04:19:26 UTC, Ola Fosheim Grøstad wrote: On Friday, 13 May 2022 at 03:31:53 UTC, Ali Çehreli wrote: On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, > by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? I suggest: patterns for @nogc allocation and where D is going with move semantics and reference counting. Basically, where is D heading with @nogc? Take each pattern from c++ and Rust and show the D counter part, with an objective analysis that covers pitfalls and areas that need more work. I feel that it'd be best if any video discussion/talk about move semantics happens _after_ [DIP 1040](https://github.com/dlang/DIPs/blob/72f41cffe68ff1f2d4c033b5728ef37e282461dd/DIPs/DIP1040.md#initialization) is merged/rejected, so that the video doesn't become irrelevan after only a few years. I think the purpose of conferences is to assess the current state and be forward looking. After 14 months I would expect Walter to know if it is going to be put to rest or not, so just email him I guess?
Re: Back to Basics at DConf?
On 5/12/22 21:41, Tejas wrote: > Or a presentation on ranges can also be good, considering how the de > facto best online article on it(by HS Teoh) is from 2013 I think the best person to give that presentation would be its awesome author. ;) Ali
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 03:31:53 UTC, Ali Çehreli wrote: On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? Ali DIP 1000 would be a good start :P Or a presentation on ranges can also be good, considering how the de facto best online article on it(by HS Teoh) is from 2013
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 04:19:26 UTC, Ola Fosheim Grøstad wrote: On Friday, 13 May 2022 at 03:31:53 UTC, Ali Çehreli wrote: On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? I suggest: patterns for @nogc allocation and where D is going with move semantics and reference counting. Basically, where is D heading with @nogc? Take each pattern from c++ and Rust and show the D counter part, with an objective analysis that covers pitfalls and areas that need more work. I feel that it'd be best if any video discussion/talk about move semantics happens _after_ [DIP 1040](https://github.com/dlang/DIPs/blob/72f41cffe68ff1f2d4c033b5728ef37e282461dd/DIPs/DIP1040.md#initialization) is merged/rejected, so that the video doesn't become irrelevan after only a few years.
Re: Back to Basics at DConf?
On Friday, 13 May 2022 at 03:31:53 UTC, Ali Çehreli wrote: On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? I suggest: patterns for @nogc allocation and where D is going with move semantics and reference counting. Basically, where is D heading with @nogc? Take each pattern from c++ and Rust and show the D counter part, with an objective analysis that covers pitfalls and areas that need more work.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 20:49:08 UTC, Chris Katko wrote: In D, I can do the module based method, but nothing short of renaming variables gives me a list of violations and, that also makes all the correct internal accesses wrong. Because private doesn't work. Call it whatever keyword you want, I really want a 'private' specifier for classes. It's incredibly useful. We can really add a keyword such as `secret`. `Good idea`.
Re: Back to Basics at DConf?
On 5/12/22 18:56, forkit wrote: > So...you want to do a talk that challenges D's complexity, by getting > back to basics? I wasn't thinking about challenging complexity but it gives me ideas. I am looking for concrete topics like templates, classes, ranges, rvalues, etc. Are those interesting? Ali
Re: Back to Basics at DConf?
On Thursday, 12 May 2022 at 21:58:33 UTC, Ali Çehreli wrote: I am considering proposing a presentation for DConf 2022. Would a "Back to Basics" style presentation be interesting? If, so what exact topic would you like to see? There was a book from my childhood. Its name is "Temel Basic", here it is https://www.nadirkitap.com/temel-basic-guzin-sagkan-tunc-gercek-kitap10256791.html The interesting thing is that the meaning of the Turkish word (Temel) and the name of the language (Basic) are the same. In other words, one is Turkish, the other is English, but in the same place and in a different sense. In summary, the basics are good. I don't like dependence at all. Simple things are beautiful...:) SDB@79
Re: What are (were) the most difficult parts of D?
On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: What are you stuck at? What was the most difficult features to understand? etc. The concept of traits (std.traits) confuses me enough. Actually the problem is that the interface is disorderly (disorganizedly). As if it was very difficult to establish a hierarchical system... Also, multitasking is like that, it's disorganizedly: taskPool.parallel(std.parallelism), yield(std.concurrency), ThreadGroup(core.thread)...etc(pufff!) SDB@79
Re: Back to Basics at DConf?
On Thursday, 12 May 2022 at 21:58:33 UTC, Ali Çehreli wrote: I am considering proposing a presentation for DConf 2022. Would a "Back to Basics" style presentation be interesting? If, so what exact topic would you like to see? For ideas, here is what CppCon 2021 had on their track: https://cppcon2021.sched.com/?searchstring=Back+to+Basics Ali So...you want to do a talk that challenges D's complexity, by getting back to basics? I'm afraid the ship has sailed :-(
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 17:34:30 UTC, H. S. Teoh wrote: Why is TLS by default a problem? It's not really for optimization, AIUI, it's more for thread safety: module-global state is TLS by default, so you don't accidentally introduce race conditions. What you accidentally have instead is people expecting top-level to be global and instead you get TLS, so it's a surprise. I mean, a lot of things works like C and C++, but not that. It's a problem because it goes from solving "no accidental race condition" and you get "people forget to add shared or __gshared and their shared library silently fail" situation. You could have none of that with explicit TLS. - `shared static this()` vs `static this()` is another trap. One is per-process, one is per-thread. Why is this a trap? Well because you can get that wrong. You get to initialize "__gshared" variables in "shared static this". It's not hard, but it's something more to explain. I wouldn't sweat it if I couldn't easily add `pure` to an entire codebase -- it hardly makes any difference anyway. If it doesn't make a difference to the bottom-line then why keep it? you're on your own and you take responsibility for any problems that you may inadvertently introduce by using the escape hatch. Well sizeable @afe code has heaps of @trusted code, so the escape hatch is very routine. it's none of the users' business. I'm not disagreeing about @trusted in API. But I was remarking in practice that @safe would mean different invariants. it's not a big issue, I was probably ranting. IOW, public APIs should always be @safe or @system. @trusted should only appear on internal APIs. Good rule to follow, TIL. So I'm curious, what exactly is it about UFCS chains that make it less maintainable? Probably personal preference, I mostly write the pedestrian way, so that debugging/optimization goes faster (maybe wrong, dunno). In the dlang.org example: void main() { stdin .byLineCopy .array .sort!((a, b) => a > b) // descending order .each!writeln; } This code has a number of prerequisites to be able to read: why is ".array" needed, why is it ".byLineCopy" vs ".byLine", is the sort stable, etc. It's just requires more time spent with the language.
Back to Basics at DConf?
I am considering proposing a presentation for DConf 2022. Would a "Back to Basics" style presentation be interesting? If, so what exact topic would you like to see? For ideas, here is what CppCon 2021 had on their track: https://cppcon2021.sched.com/?searchstring=Back+to+Basics Ali
Re: Creating a custom iota()
On Thursday, 12 May 2022 at 20:12:19 UTC, Ali Çehreli wrote: And I've been thinking 'iota' may not be as suitable as I thought at first. I like the following even more: auto r0 = st .by(Duration(2)) .take(5); So I wrote this by() for my DateTime and then: import quantities.si; auto by(in DateTime begin, in Frequency f){ return begin.by(1/f); } //This let me do: now.by(60*hertz) .until!"a>b"(now+1*second) .each!writeln; My mind is blowing! :D
Re: Creating a custom iota()
On Thursday, 12 May 2022 at 17:06:39 UTC, Ali Çehreli wrote: I don't care whether it is good practice or not. :) The following is what you meant anyway and seems to work. I restricted the parameter types to the ones I wanted to use. And for the standard iota behavior I used a public import. public import std.range : iota; auto iota(in DateTime begin, in DateTime end, in Time step){ //https://forum.dlang.org/post/ivskeghrhbuhpiyte...@forum.dlang.org -> Ali's solution static struct Result{ DateTime current, end; Time step; @property bool empty(){ return current >= end; } @property auto front(){ return current; } void popFront(){ assert(!empty); current += step; } } return Result(begin, end, step); } ... iota(st, en, day).each!writeln; //works iota(1, 10, 0.5).each!writeln; //also works It works perfectly, Thank You very much! Although that general implementation of iota is a bit complex for me, this specialized one is simple. note(0): no cast() was needed here, worked with a const DateTime{ ulong ticks; ... }
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 16:04:09 UTC, Ali Çehreli wrote: My view on private has changed over the years. I need to be convinced that there is usage that needs to be protected. :) I don't see people using types freely especially the ones that are in the same module. The only argument for private is to allow changing the implementation of published libraries in the future. I use private as part of my rapid dev process. You write code, you get things working with no real worry for correctness or careful interfaces. You cannot make an interface until you actually know what you're making. So you make things, with "bad" connections. Then you remove those connections. 1. Get system working with lots of direct access to class variables. 2. Make those variables forbidden (through private in C++). 3. The compiler now shows you every instance of your new interface encapsulation violations. No human decision to opt-in. No remembering to search. You have an automatically generated list of violations to fix. I do the same thing with a module called "g" (for globals). I write new code into g, get it working. I can see how "dirty" a file is by simply searching for how many references to the module g there are. Then if I move the code into a proper new module, all references to g magically fail. It is impossible for me to leave dangling old code touching naughty internals, and I get a nice error view of all areas that need attention. If the uses are all over the place and not in only a few areas (instead of just in logic() and draw(), but all over the place) then I know I need to rewrite and introduce a system so everything is mostly in one place. In D, I can do the module based method, but nothing short of renaming variables gives me a list of violations and, that also makes all the correct internal accesses wrong. Because private doesn't work. Call it whatever keyword you want, I really want a 'private' specifier for classes. It's incredibly useful.
Re: Creating a custom iota()
On 5/12/22 12:51, ag0aep6g wrote: >> auto iota(B, E, S)(B begin, E end, S step) > [...] >> { >> static struct Result >> { >> B current; > [...] >> void popFront() >> { > [...] >> current += step; >> } >> } > [...] >> } > > Mark iota's `begin` parameter as const. Then you don't need the cast, > because `B` will be mutable. Cool trick! Like this: auto iota(B, E, S)(const(B) begin, E end, S step) { // ... } It works with non-const values as well. So apparently it makes the function parameter const(B) and deduces B to be the non-const version of that, which always produces the non-const version. And I've been thinking 'iota' may not be as suitable as I thought at first. I like the following even more: auto r0 = st .by(Duration(2)) .take(5); auto r1 = st .by(Duration(2)) .until(en); A family of 'by' ovenloads can be defined or it can be templatized to be used as 'by!Duration(2)' etc.: auto by(DateTime dt, Duration dur) { struct Result { DateTime front; Duration dur; enum empty = false; void popFront() { front += dur; } } return Result(dt, dur); } Just works. But one may want to provide an accessor for front(). Ali
Re: Creating a custom iota()
On Thursday, 12 May 2022 at 16:57:35 UTC, H. S. Teoh wrote: Does your DateTime type support the `++` operator? It can't because I only want to use the quantities.si.Time type to do arithmetic with my DateTime. In my previous DateTime, it was a lot of problem that I was doing math on it's raw internal variable (which was a double where 1.0 meant 1 day.) In the new version adding int(1) does a compilation error. I will use 1*second or 1*day or 1*micro(second) instead. I will always state the measurement unit to avoid confusions. But I'm curious, why didn't you use std.datetime? There are many weird reasons: 5 years ago I moved to DLang from Delphi. Since 20 years I always used the old Borland date system whist stards in 1899, is an ieee double, 1 = 1 day. I only did stuff with local times, it was enough. Recently I had to work with Python as well, and there I started to have problems with time synchronizations between the 2 systems. I ended up sending the exact Borland time to the Python program and make my little routines to work with them exactly like I do 20 years ago in Delphi, 5 years ago in DLang. But I know it is not nice. So a week ago I discovered the quantities package and I decided to rewrite my DateTime to use the Time type in that. It solves all my measurement unit madness in a very elegant way. So I also want those measurement units working in all my systems. (I have lengths, frequencies too) For me std.datetime was not an option because that felt so big I scared of it at the first look. It's 1.5MB, the same size as my complete program I'm working on :D I also hade a second based time measurement 'system', it used QueryPerformanceCounter. I want do discontinue that as well. So these are the features of the new DateTime: - small size: 64 uint is the internal format. (Half of std.systemtime, but it lacks timezone, it's only UTC internally). - precise: 100.0/64 nanosecond is the smallest unit. It covers 913 years. - It was built around the new WinAPI GetSystemTimePreciseAsFileTime() It gives me 100ns resolution UTC time in less than 50ns. So that's why I don't need QueryPerformanceCounter anymore. - The extra 6 bits under the 100ns ticks will be used for time based unique ID generation. It's better for me than having 6 years at my hand. - The integration with quantities.si makes my work much easier. I can't wait to use it in my program, as I knows physics things better than me, haha. std.range.recurrence. Indeed, that's an option as well, I forgot about. Thank You!
Re: What are (were) the most difficult parts of D?
On 5/12/22 12:00, Paul Backus wrote: > Good news: starting from DMD 2.099, this error message has been > reworded. Instead of "cannot deduce function...". it now says: > > Error: none of the overloads of template `std.algorithm.iteration.sum` > are callable using argument types `!()(int[3])` Much better. An idea: The compiler should be able to detect static arrays and also suggest slicing with something like "slicing as in `arr[]` might work". Ali
Re: Creating a custom iota()
On Thursday, 12 May 2022 at 17:06:39 UTC, Ali Çehreli wrote: void main() { const st = DateTime(Duration(0)); [...] // (0) I think D should not insist on 'const' // when copying types that have no indirections. // We shouldn't need the cast() below in this case. [...] iota(cast()st, en, step).each!writeln; } [...] auto iota(B, E, S)(B begin, E end, S step) [...] { static struct Result { B current; [...] void popFront() { [...] current += step; } } [...] } Mark iota's `begin` parameter as const. Then you don't need the cast, because `B` will be mutable.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 15:17:10 UTC, Adam D Ruppe wrote: It is simpler than it looks, I wrote about it in my book and in a post here: https://forum.dlang.org/post/xklcgjaqggihvhctc...@forum.dlang.org "Then commas separate the definitions of each placeholder variable, just as if they were template argument definitions [...]" That... makes sense, I didn't think of them like that.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 16:48:05 UTC, H. S. Teoh wrote: static foreach isn't meant to handle large loops. Writing `static foreach (i; 0 .. 6)` is generally a bad idea; my suspicion is that the compiler ran out of stack space). It's more for unfolding groups of statements or declarations like cases in a switch-statement. I understand, but I don't think I had any static foreaches in my code at the time. My case was more comment #10.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 18:07:05 UTC, H. S. Teoh wrote: On Thu, May 12, 2022 at 09:04:09AM -0700, Ali Çehreli via Digitalmars-d-learn wrote: Error: template `std.algorithm.iteration.sum` cannot deduce function from argument types `!()(int[3])` /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: `sum(R)(R r)` with `R = int[3]` must satisfy the following constraint: ` isInputRange!R` WHAT? :) But the clue is on the last line above. [...] Seriously though, that error message is horrendously ugly. I mean I've seen it thousands of times by now, so I know what it means and where to look for the actual problem. But it's eminently unfriendly to someone who doesn't already know the language very well. Good news: starting from DMD 2.099, this error message has been reworded. Instead of "cannot deduce function...". it now says: Error: none of the overloads of template `std.algorithm.iteration.sum` are callable using argument types `!()(int[3])`
Re: What are (were) the most difficult parts of D?
On Thu, May 12, 2022 at 09:04:09AM -0700, Ali Çehreli via Digitalmars-d-learn wrote: > On 5/11/22 18:06, Christopher Katko wrote: > > > Cool useful library functions like sumElement that magically don't > > work on static arrays. > > Yeah, that sometimes gets me as well. Although it is trivial to deal > with, the programmer may be surprised by the strange error messages: > > int[3] arr = [ 1, 2, 3 ]; > assert(sum(arr) == 6); > > Error: template `std.algorithm.iteration.sum` cannot deduce function from > argument types `!()(int[3])` > /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: > `sum(R)(R r)` > with `R = int[3]` > must satisfy the following constraint: > ` isInputRange!R` > > WHAT? :) But the clue is on the last line above. [...] Seriously though, that error message is horrendously ugly. I mean I've seen it thousands of times by now, so I know what it means and where to look for the actual problem. But it's eminently unfriendly to someone who doesn't already know the language very well. T -- A mathematician learns more and more about less and less, until he knows everything about nothing; whereas a philospher learns less and less about more and more, until he knows nothing about everything.
Re: What are (were) the most difficult parts of D?
On Thu, May 12, 2022 at 01:06:02AM +, Christopher Katko via Digitalmars-d-learn wrote: [...] > Cool useful library functions like sumElement that magically don't > work on static arrays. Just slice it with []: int[5] data = [ 1, 2, 3, 4, 5 ]; auto sum = data[].sumElement; The main reason is that static arrays cannot shrink (their length is constant), so they don't qualify as ranges. No problem, [] takes a slice of them that *can* shrink. > 'private' is per module, not per class, making it pretty much useless > for preventing incorrect access and using . This is a common complaint. But IME, I haven't really run into problems with it. Accessing private members really only becomes a problem when you have multiple separate modules interacting with each other. If a module has grown large enough that this starts becoming a problem, it's usually a sign that it's time to refactor the module into two (or more) smaller ones. > completely different semantics for a class vs a struct. Is it a > reference? Is it a value? Look up the entire declaration and have the > entire Dlang manual open to find out. class == by reference struct == by value Very straightforward. > As far as I remember, no automatic RAII support, even though it's > insanely useful. You have to manually write scope(end) stuff which > means any person forgetting one is now leaking memory. ??? Structs with dtors have RAII. You only need scope(exit) if you're manually managing resources. What exactly are you referring to here? > Writing output in a deconstuctor (for learning) works. But then you > accidentally combine two strings inside it and the garbage collecter > crashes without a stack trace. Yeah, class dtors and GC don't mix, in general. There was a proposal to remove class dtors from the language some years ago. But it didn't happen, probably because more people complained about that than about dtors not being allowed to allocate memory or access GC'd resources. :-D > Documentation. Documentation. Documentation. [...] What exactly is wrong with the docs? A concrete list of actionable items would be nice. (I admit the docs could use some improvements, btw.) T -- "I'm not childish; I'm just in touch with the child within!" - RL
Re: What are (were) the most difficult parts of D?
On Wed, May 11, 2022 at 06:43:39PM +, Guillaume Piolat via Digitalmars-d-learn wrote: > On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: > > What are you stuck at? What was the most difficult features to > > understand? etc. > > - How to do deterministic destruction with programs that use > everything (struct / class / dynamic dispatch / GC / manual / > etc). This requires to understand what the runtime does, what the > gc does. I'm not sure I fully understand what you're trying to say here. How does GC mix with deterministic destruction? I thought by the very nature of GC, destruction is non-deterministic. If you want deterministic destruction, don't use the GC...? > Interesting nonetheless. > > - Some traps. Accidental TLS is a thing, top-level should probably > not be silently TLS. > People will loose hours on this completely preventable thing. > What was the idea, optimize code without people knowing? Why is TLS by default a problem? It's not really for optimization, AIUI, it's more for thread safety: module-global state is TLS by default, so you don't accidentally introduce race conditions. > - `shared static this()` vs `static this()` is another trap. One is per-process, one is per-thread. Why is this a trap? [...] > - Some features lack an escape hatch, notably `pure`. pure leaks > into identifiers, like `pureMalloc`. Trying to add `pure` fails on > a large codebase. IMNSHO, pureMalloc is a code smell. It should not have been added in the first place. But more to the point: pure is of limited utility. Perhaps the most useful application is the initialization of immutable data structures constructed by a mutable factory method. But other than that, I don't find very much use for it in practice. I wouldn't sweat it if I couldn't easily add `pure` to an entire codebase -- it hardly makes any difference anyway. > - `@safe`/`@trusted`/`@system` is good but the definition of what > `@trusted` means has to be remembered from the programmer. But isn't that the nature of all escape hatches? An escape hatch by definition means you're operating outside of the abstractions provided by the compiler; IOW you're on your own and you take responsibility for any problems that you may inadvertently introduce by using the escape hatch. > For example `Mutex.lock()` is `@trusted`, it could have been > `@system` to let user review their usage of locks. You have to > wonder "can a lock()/unlock() corrupt memory?". People can use > that to mean "@reviewed" instead. Because it is up to us, the > exact meaning will float in the D subcultures. A function which > has been marked `@trusted` does not receive any review whan > changed later. It will not mean the same as `@trusted` in > another codebase. IMNSHO, @trusted should never be used in public-facing APIs. It's really an implementation detail -- "this code does something using potentially dangerous operations, but we reviewed it carefully to make sure it's safe to call from @safe code". The caller does NOT need to know this; as far as the caller is concerned, it's calling a @safe function. That's all it knows and all that it should care about. How this @safe function is implemented -- using completely @safe operations or potentially dangerous operations (@trusted) isn't something the user should care about. That's something the author of the module needs to care about, but it's none of the users' business. IOW, public APIs should always be @safe or @system. @trusted should only appear on internal APIs. > - Generic code typically has bad names (domain-less) and worse > usability. It's often not pretty to look at. Mostly cultural, > since D has powerful templates so they had to be everywhere. UFCS > chains are not that convincing when you are worried about > maintenance. I'm puzzled by this. I use (and write!) generic code all the time and they have been great. UFCS chains are awesome; they allow me to express a series of data transformations in a very concise way, so that I can keep the high-level logic of the function readable, without having to break it into separate functions. This, plus `auto` type inference, makes the code *more* maintainable, IME, because I can shuffle components of the UFCS chain around without needing to rewrite the types of a bunch of helper functions. So I'm curious, what exactly is it about UFCS chains that make it less maintainable? > Phobos take short names for itself, this leads to pretty > complicated operations having a small screen estate. I'm also puzzled by this. Why is this a problem? > - `assert(false)` being different and not removed by `-release`. > Keyword reuse seems entrenched but honestly a "crash here" keyword > would be more readable. noreturn crashHere() { assert(false); } void main() {
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 16:24:26 UTC, Ali Çehreli wrote: Cool trick but "parent" confused me there. I think you mean "base". :) https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming mentions "base class" as much as "parent class"
Re: Creating a custom iota()
On 5/12/22 04:57, realhet wrote: > //this would be nicer, but not works > iota(st, en, day).each!writeln; For others, the problem is, iota does have a version that works with user types but not one that parameterizes 'step'. An oversight? > My question is, is there a way to 'extend' the functionality of the > std.iota() function or it is better to come up with a unique name for > this special 'iota' functionality? I think ioat can be improved to work with user 'step' types as I did below. > Is this a good practice I don't care whether it is good practice or not. :) The following is what you meant anyway and seems to work. I added 6 comments: import std.stdio; import std.range; import std.algorithm; struct Duration { ulong value; } struct DateTime { Duration sinceEpoch; // Quickest implementation for this post auto opOpAssign(string op)(Duration dur) if (op == "+") { return DateTime(Duration(sinceEpoch.value += dur.value)); } } void main() { const st = DateTime(Duration(0)); const en = DateTime(Duration(10)); const step = Duration(1); // (0) I think D should not insist on 'const' // when copying types that have no indirections. // We shouldn't need the cast() below in this case. // // Alternatively, the implementation of iota() // could use Unqual after detecting B has no // indirections. That would be better for the // user but again, the language should copy // to non-const by-default. But then, I am // sure there would be cases where an unexpected // function overload might be selected in some // cases. iota(cast()st, en, step).each!writeln; } // I adapted the following template from my // /usr/include/dlang/dmd/std/range/package.d // and then: // (1) Added 'S step' auto iota(B, E, S)(B begin, E end, S step) // (2) Removed for now // if (!isIntegral!(CommonType!(B, E)) && // !isFloatingPoint!(CommonType!(B, E)) && // !isPointer!(CommonType!(B, E)) && // is(typeof((ref B b) { ++b; })) && // (is(typeof(B.init < E.init)) || is(typeof(B.init == E.init))) ) { static struct Result { B current; E end; S step; // (3) Added @property bool empty() { static if (is(typeof(B.init < E.init))) return !(current < end); else static if (is(typeof(B.init != E.init))) return current == end; else static assert(0); } @property auto front() { return current; } void popFront() { assert(!empty); // (4) Used += instead of ++current // This can be improved to use the other // method a.l.a. "design by introspection". current += step; } } // (5) Added step return Result(begin, end, step); } Ali
Re: Creating a custom iota()
On Thu, May 12, 2022 at 11:57:54AM +, realhet via Digitalmars-d-learn wrote: [...] > I have my own DateTime struct. > It has opCmp() and opBinary(), I can do arithmetic with this custom > DateTime and the amazing time units of the **quantities** package. > > Now I'm about mo make iterations in a DateTime range: > > const > st = DateTime(UTC, "22.1.1 8:30").utcDayStart, > en = DateTime(UTC, "22.3.5 19:56").max(now).utcDayStart + > (100.0/64)*nano(second); > > //this works > for(auto d = cast()st; d < en; d += day) writeln(d); > > //this would be nicer, but not works > iota(st, en, day).each!writeln; > > My question is, is there a way to 'extend' the functionality of the > std.iota() function or it is better to come up with a unique name for > this special 'iota' functionality? Custom user types should already be supported by iota; see: https://issues.dlang.org/show_bug.cgi?id=10762 Does your DateTime type support the `++` operator? If not, that's the most likely reason iota failed to instantiate on it. Just add `opUnary(string op : "++")` to your type, and it should work. [...] > Or maybe put it inside a DateTimeRange struct, and implement the std > range functionality? [...] That would work too. But I'm curious, why didn't you use std.datetime? The DateTime type there supports inter-date arithmetic (as far as it makes sense), and can be easily made into a range using std.range.recurrence. T -- When solving a problem, take care that you do not become part of the problem.
Re: What are (were) the most difficult parts of D?
On Thu, May 12, 2022 at 02:42:43PM +, Anonymouse via Digitalmars-d-learn wrote: [...] > The one thing that has caused me most anguish and woe is hands-down > https://issues.dlang.org/show_bug.cgi?id=18026 though. It hasn't bit > me for a while now, but the feeling of uncertainty, that the compiler > might just suddenly after an innocent change no longer compile your > project, seemingly outside of your control, is just... disheartening > when it happens. static foreach isn't meant to handle large loops. Writing `static foreach (i; 0 .. 6)` is generally a bad idea; my suspicion is that the compiler ran out of stack space). It's more for unfolding groups of statements or declarations like cases in a switch-statement. For complex loops, what you really want is to use CTFE, which has a proper interpreter that can execute real code, instead of static foreach. What I'd do in the case described in comment 20 is to use CTFE to generate an array of indices that satisfy the predicate (it can create this array however it wants), then static foreach over this array, instead of iterating from 0 to 6 directly. Or, in certain cases, you might want to just try straight foreach instead of static foreach, just make a tuple of your indices first and it will auto-unroll. T -- Не дорог подарок, дорога любовь.
Re: What are (were) the most difficult parts of D?
On Thu, May 12, 2022 at 12:13:32PM +, Basile B. via Digitalmars-d-learn wrote: [...] > Problem is more (from https://dlang.org/spec/expression.html#is_expression) > > ``` > is ( Type : TypeSpecialization , TemplateParameterList ) > is ( Type == TypeSpecialization , TemplateParameterList ) > is ( Type Identifier : TypeSpecialization , TemplateParameterList ) > is ( Type Identifier == TypeSpecialization , TemplateParameterList ) > ``` > > I never remember those variants, because basically you never need > them... They were required for std.traits and that's it. Not true. I use these all the time in generic code. Basically, they allow you to do IFTI-like template pattern-matching using static-if's. This is eminently useful for inspecting incoming types in template functions. For example, in serialization code, I would do something like: auto serialize(T)(T data) { static if (is(T == string)) { ... // straightforward string encoding } else static if (is(T : U[], U)) // this means: "T matches the pattern `U[]`, // where U is some arbitrary type" { ... // non-string array encoding // note that in this block, `U` is defined to be // the array element; very convenient for // further type dissection } else static if (is(T : U[V], U, V)) // this means: "T matches the pattern `U[V]`, // where U and V are arbitrary types" { ... // AA encoding // similarly, in this block U is the value type // and V is the key type, very convenient for // further type dissection } else static if (is(T : MyType!(U), string U)) // this means: "T matches the pattern // `MyType!(U)` where U is some string" { ... // special handling for instantiations of // MyType with string argument // in this block, U == string } ... // and so on } I concede that the documentation isn't exactly easy to understand on a first read; it took me many tries before it "clicked". But once you understand the general pattern, most of the cases make sense and is pretty predictable. There *are* one or two special cases, granted, but those are exceptional and there are already std.traits wrappers that expose a friendlier API. The worst offender in this category is __parameters, about which I wrote years ago here: https://forum.dlang.org/thread/vpjpqfiqxkmeavtxh...@forum.dlang.org Still, putting this ugly special case aside, the rest of is(...) syntax mostly conforms to the above pattern, and is readily understandable once you learn the pattern. T -- Written on the window of a clothing store: No shirt, no shoes, no service.
Re: What are (were) the most difficult parts of D?
On 5/12/22 07:28, Guillaume Piolat wrote: > On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote: >> - Certain variant forms of the `is` Expression are not obvious (not >> intuitive), I'm pretty sure I still cant use them without a quick look >> to the specs. > > That one was a trouble to hear about => > http://p0nce.github.io/d-idioms/#Get-parent-class-of-a-class-at-compile-time Cool trick but "parent" confused me there. I think you mean "base". :) It looks like there is an alternative now: https://dlang.org/phobos/std_traits.html#BaseTypeTuple Ali
Re: What are (were) the most difficult parts of D?
On 5/11/22 19:35, zjh wrote: > On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: >> What are you stuck at? What was the most difficult features to >> understand? etc. >> > > I don't know the progress of `interface to C++`. > I want to use my C++ functions in `d`. That direction is easier: https://dlang.org/spec/cpp_interface.html#calling_global_d_functions_from_cpp (Also see "Using D Classes From C++" on the same page.) The problem is calling into C++ where C++ templates are involved. As D does not include a C++ compiler, it cannot instantiate C++ templates automatically. (The programmer must instantiate explicitly as needed on the C++ side.) Ali
Re: What are (were) the most difficult parts of D?
On 5/11/22 18:06, Christopher Katko wrote: > Cool useful library functions like sumElement that magically don't work > on static arrays. Yeah, that sometimes gets me as well. Although it is trivial to deal with, the programmer may be surprised by the strange error messages: int[3] arr = [ 1, 2, 3 ]; assert(sum(arr) == 6); Error: template `std.algorithm.iteration.sum` cannot deduce function from argument types `!()(int[3])` /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: `sum(R)(R r)` with `R = int[3]` must satisfy the following constraint: ` isInputRange!R` WHAT? :) But the clue is on the last line above. For completeness and for people who may not know the reason, D's static arrays and dynamic arrays are different in a number of ways but what matters here is that static arrays are not ranges because they cannot shrink. (Arguably, static arrays could be RandomAccessRanges but D's range hierarchy does not allow RandomAccessRanges that are not also InputRanges and ForwardRanges.) So, the commented-out assert below cannot be compiled but the two following lines do compile by simply adding the two characters [] to get a range to all elements: import std.algorithm; void main() { int[3] arr = [ 1, 2, 3 ]; // assert(sum(arr) == 6); assert(sum(arr[]) == 6); assert(arr[].sum == 6); } > 'private' is per module, not per class, making it pretty much useless > for preventing incorrect access and using . My view on private has changed over the years. I need to be convinced that there is usage that needs to be protected. :) I don't see people using types freely especially the ones that are in the same module. The only argument for private is to allow changing the implementation of published libraries in the future. Still, private could have been a convention like naming variables with an underscore (which Go chose) and it could have been as effective. People who went around the convention and accessed the private members would either be happy or deserved what they got. I really don't see any problem on this matter for a programming language to go out of their way to protect people from themselves. I started wondering as I wrote those: Perhaps IDEs make this a bigger issue? If they do respect private/public, perhaps they include member names in menus to pick from and the programmer does not want to see the private members there? > I just realized foreach copies by value by default. Maybe. Sometimes. > When? It is always by-value when passing parameters and in foreach (which can be defined by opApply) and everywhere else. As Steve said, the confusion is when the copied thing is a reference itself. You end up getting another reference to data. Ali
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 15:32:24 UTC, Adam D Ruppe wrote: On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote: What's the difference between a Type and Type Identifier? The is expression roughly follows variable declaration style. You write int a; to declare a new symbol named `a` of type `int`. Similarly, static if(is(T a)) declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.) The Identifier is optional. Ah, yeah I know about that.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 15:31:03 UTC, Steven Schveighoffer wrote: On 5/12/22 11:18 AM, jmh530 wrote: On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote: [snip] ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it. What's the difference between a Type and Type Identifier? Type is a type, Identifier is an identifier. In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type. So e.g.: ```d static if(is(Foo Bar == struct)) { // inside here, it was determined that `Foo` was a type, and it is a // struct, and now, `Bar` is aliased to `Foo` } ``` It's very confusing syntax though. -Steve yess that kind of stuff
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote: What's the difference between a Type and Type Identifier? The is expression roughly follows variable declaration style. You write int a; to declare a new symbol named `a` of type `int`. Similarly, static if(is(T a)) declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.) The Identifier is optional.
Re: What are (were) the most difficult parts of D?
On 5/12/22 11:18 AM, jmh530 wrote: On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote: [snip] ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it. What's the difference between a Type and Type Identifier? Type is a type, Identifier is an identifier. In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type. So e.g.: ```d static if(is(Foo Bar == struct)) { // inside here, it was determined that `Foo` was a type, and it is a // struct, and now, `Bar` is aliased to `Foo` } ``` It's very confusing syntax though. -Steve
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote: On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote: [snip] ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it. What's the difference between a Type and Type Identifier? `int`, `char` and friends are `Type` In `int a`, `string c`, `a` and `c` are `Identifier`s
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote: [snip] ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it. What's the difference between a Type and Type Identifier?
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 14:42:43 UTC, Anonymouse wrote: That said, one thing I cannot seem to firmly wrap my head around is `is` expressions. `is` does so many things. It is simpler than it looks, I wrote about it in my book and in a post here: https://forum.dlang.org/post/xklcgjaqggihvhctc...@forum.dlang.org ``` alias AA = long*[string]; static if (is(AA whatEvenGoesHere : VP[K], VP, K)) You don't have to put anything there. The is expression kinda parallels declarations, so that thing would be the name for the newly declared symbol. But you don't need to declare a new symbol there so you can leave it blank; most the pieces are optional. The one thing that has caused me most anguish and woe is hands-down https://issues.dlang.org/show_bug.cgi?id=18026 though. yeah bugs happen.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 14:06:13 UTC, Arjan wrote: On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote: On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: - Operator overloading in certain cases was confusing, I remember that for one particular form once I had to use your book instead of the official specs (when opSlice and opIndex are combined) I still have the thing : ```d /** * CharMap is an helper struct that allows to test * if a char is within a set of characters. */ struct CharMap { private bool[] _map; private dchar _min, _max; private void setMinMax(dchar value) pure nothrow @safe { if (value <= _min) _min = value; else if (value >= _max) _max = value; _map.length = _max + 1 - _min; } /** * Used in the construction process. * * Params: * lo = The dchar that defines the range lower bound. * hi = The dchar that defines the range upper bound (inclusive). * * Examples: * --- * CharMap cm = CharMap['0'..'9']; * --- */ static CharRange opSlice(int index)(dchar lo, dchar hi) pure nothrow @safe @nogc { return CharRange(lo, hi); } /** * Used in the construction process. * * Params: * a = A list made of character slices, of single characters or * * any other values whose type is implicitly convertible to dchar. * * Examples: * --- * CharMap cm = CharMap['0'..'9', '.', 'f', 'd', 38, 39]; * --- */ static CharMap opIndex(A...)(A a) pure nothrow @safe { CharMap result; // bounds foreach(elem; a) { alias T = typeof(elem); static if (isSomeChar!T || isImplicitlyConvertible!(T, dchar)) { result.setMinMax(elem); } else static if (is(T == CharRange)) { result.setMinMax(elem._min); result.setMinMax(elem._max); } else static assert(0, "unsupported opIndex argument type: " ~ T.stringof); } result._map[] = false; foreach(elem; a) { alias T = typeof(elem); static if (isSomeChar!T || isImplicitlyConvertible!(T, dchar)) result._map[elem - result._min] = true; else static if (is(T == CharRange)) { foreach(size_t i; elem._min - result._min .. elem._max - result._min + 1) result._map[i] = true; } } return result; } /** * Returns true if a character is within the map. * * Params: * c = A character or any value convertible to a dchar. */ bool opBinaryRight(string op = "in", C)(C c) const pure nothrow @safe @nogc if (op == "in") { static if (isSomeChar!C || isImplicitlyConvertible!(C, dchar)) { if (_min > c || c > _max) return false; else return _map[c - _min]; } else static assert(0, `invalid argument type for CharMap.opBinaryRight!"in"(): ` ~ C.stringof); } } /// pure @safe unittest { CharMap cm = CharMap['a'..'f', '0'..'9' , 'A'..'F', '_', 9]; assert('a' in cm); assert('b' in cm); assert('c' in cm); assert('d' in cm); assert('e' in cm); assert('f' in cm); assert('g' !in cm); assert('A' in cm); assert('B' in cm); assert('C' in cm); assert('D' in cm); assert('E' in cm); assert('F' in cm); assert('G' !in cm); assert('0' in cm); assert('4' in cm); assert('9' in cm); assert('_' in cm); assert('%' !in cm); assert('\t' in cm); } ```
Re: What are (were) the most difficult parts of D?
On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: What are you stuck at? What was the most difficult features to understand? etc. I came from shell scripts. They grew too large and overly complex when I wanted to do non-trivial things in a neat way, so I looked to proper programming languages and arbitrarily settled on D over python and similar. So for me the norm is D, and everything else is "other languages". That said, one thing I cannot seem to firmly wrap my head around is `is` expressions. `is` does so many things. There's probably more intricate examples of how it's confusing, but I don't know it well enough to construe one: ``` alias AA = long*[string]; static if (is(AA whatEvenGoesHere : VP[K], VP, K)) { static if(is(VP : V*, V)) { assert(is(V)); } } ``` The one thing that has caused me most anguish and woe is hands-down https://issues.dlang.org/show_bug.cgi?id=18026 though. It hasn't bit me for a while now, but the feeling of uncertainty, that the compiler might just suddenly after an innocent change no longer compile your project, seemingly outside of your control, is just... disheartening when it happens.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote: - Certain variant forms of the `is` Expression are not obvious (not intuitive), I'm pretty sure I still cant use them without a quick look to the specs. That one was a trouble to hear about => http://p0nce.github.io/d-idioms/#Get-parent-class-of-a-class-at-compile-time
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote: On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: What are you stuck at? What was the most difficult features to understand? etc. To make it more meaningful, what is your experience with other languages? Ali Overhall I think that D was not hard to learn because well designed (i.e intuitive). I concur.. A few specific points however that I remember - Certain variant forms of the `is` Expression are not obvious (not intuitive), I'm pretty sure I still cant use them without a quick look to the specs. Yes indeed, had to read through the then excellent pdf()https://github.com/PhilippeSigaud/D-templates-tutorial by Philippe Sigaud (of PEG) to grasp the whole idea first, and still have to look it up when the need to use it arises... - Operator overloading in certain cases was confusing, I remember that for one particular form once I had to use your book instead of the official specs (when opSlice and opIndex are combined) Indeed same experience. Also opCmp and opEquals caused some confusion. D's [][] !== C's [][], Range peculiarities w.r.t some algo's (algo want's fwdRange but got inputRange but did not have the constraint ea) lazy vs eager algorithms (the need to call .array) The main difficulty I had is actually not specific to D. It was to accept that a GC is OK. Nice one. I recon I have to think much harder sometimes to know where the data is and 'who' has access: stack heap tls mutexed or not whatever, but find myself almost never asking this question anymore in D, which I use(d) to do almost all the time in c++ land. The need for it is almost removed by D.
Re: Exercises
On Thursday, 12 May 2022 at 13:04:51 UTC, Alain De Vos wrote: Is there a link to a webpage with some dlang exercises in order to see if i master the language, from simple to diffucult ? [Rosetta Code](https://www.rosettacode.org) has a bunch, with [many](https://www.rosettacode.org/wiki/Category:D) examples/answers in D.
Re: Exercises
On Thursday, 12 May 2022 at 13:04:51 UTC, Alain De Vos wrote: Is there a link to a webpage with some dlang exercises in order to see if i master the language, from simple to diffucult ? [dtour](https://tour.dlang.org/).
Re: While loop on global variable optimised away?
On Wednesday, 11 May 2022 at 10:01:18 UTC, Johan wrote: Any function call (inside the loop) for which it cannot be proven that it never modifies your memory variable will work. That's why I'm pretty sure that mutex lock/unlock will work. I think the common semantics ought to be that everything written by thread A before it releases the mutex will be visible to thread B when it aquires the same mutex, and any assumptions beyond this are nonportable?
Exercises
Is there a link to a webpage with some dlang exercises in order to see if i master the language, from simple to diffucult ?
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote: On Thursday, 12 May 2022 at 11:50:59 UTC, Alain De Vos wrote: Some keywords are overloaded and have different meaning when used in a different place. Also some syntactic-sugar is way to much meaning too many different ways to do the same thing. I would prefer one way which is advised. `ptr1 is ptr2` VS `is(T==U)` is ok even if the keyword is reused for two different things. Problem is more (from https://dlang.org/spec/expression.html#is_expression) ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it. Perfect example of reuse that is never a problem : `final`. what statically does `is` should have been several `__traits` I think.
Re: What are (were) the most difficult parts of D?
On Thursday, 12 May 2022 at 11:50:59 UTC, Alain De Vos wrote: Some keywords are overloaded and have different meaning when used in a different place. Also some syntactic-sugar is way to much meaning too many different ways to do the same thing. I would prefer one way which is advised. `ptr1 is ptr2` VS `is(T==U)` is ok even if the keyword is reused for two different things. Problem is more (from https://dlang.org/spec/expression.html#is_expression) ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it.
Creating a custom iota()
Hello, I have my own DateTime struct. It has opCmp() and opBinary(), I can do arithmetic with this custom DateTime and the amazing time units of the **quantities** package. Now I'm about mo make iterations in a DateTime range: const st = DateTime(UTC, "22.1.1 8:30").utcDayStart, en = DateTime(UTC, "22.3.5 19:56").max(now).utcDayStart + (100.0/64)*nano(second); //this works for(auto d = cast()st; d < en; d += day) writeln(d); //this would be nicer, but not works iota(st, en, day).each!writeln; My question is, is there a way to 'extend' the functionality of the std.iota() function or it is better to come up with a unique name for this special 'iota' functionality? I know that if I'm going to patch iota in my module, I have to make ALL the iota() variants plus my special iota variant visible in that module scope. Is this a good practice, or is there a better way? Or maybe put it inside a DateTimeRange struct, and implement the std range functionality?
Re: What are (were) the most difficult parts of D?
Some keywords are overloaded and have different meaning when used in a different place. Also some syntactic-sugar is way to much meaning too many different ways to do the same thing. I would prefer one way which is advised.
Re: What are (were) the most difficult parts of D?
On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: What are you stuck at? What was the most difficult features to understand? etc. To make it more meaningful, what is your experience with other languages? Ali Overhall I think that D was not hard to learn because well designed (i.e intuitive). A few specific points however that I remember - Certain variant forms of the `is` Expression are not obvious (not intuitive), I'm pretty sure I still cant use them without a quick look to the specs. - Operator overloading in certain cases was confusing, I remember that for one particular form once I had to use your book instead of the official specs (when opSlice and opIndex are combined) The main difficulty I had is actually not specific to D. It was to accept that a GC is OK.
Re: Virtual methods on stack objects
On Wednesday, 11 May 2022 at 20:53:21 UTC, Marvin Hannott wrote: On Wednesday, 11 May 2022 at 20:23:07 UTC, Ali Çehreli wrote: On 5/11/22 13:06, Marvin Hannott wrote: > I appreciate the answer, don't much like the "solutions". Me neither. :) > It's not so much about copying Great! > scoped class objects should have value semantics. std.typecons.scoped does exactly that: https://dlang.org/phobos/std_typecons.html#scoped import std.stdio; import std.typecons; interface Animal { string sing(); } class Cat : Animal { this() { writeln("Hi!"); } ~this() { writeln("Bye!"); } string sing() { return "mew"; } } void foo(Animal animal) { writeln(animal.sing()); } void bar() { auto cat = scoped!Cat(); foo(cat); } void main() { bar(); } The output: Hi! mew Bye! Ali Yeah, but you can't return `Cat` 😉. And the documentation for `scoped` says: It's illegal to move a class instance even if you are sure there are no pointers to it. As such, it is illegal to move a scoped object. That's kinda very limiting. Anyway, I cooked up another idea based on your first suggestions. ```D struct S { static private interface I { int f(int i); } static private final class A : I { int f(int i) {return i;} } static private final class B : I { int f(int i) {return i+ 1;} } private I i; private int d; this(int d) { this.d = d; if(d < 10) { i = scoped!A(); }else { i = scoped!B(); } } int f() { return i.f(d);} } ``` I mean, this is a super dumb example, but it kinda works. And I think it could be made a lot less tedious with some mixin magic. `scoped` is not necesary, try this: ```d import std.typecons; struct S{ static private interface I{ int f(int i)const; } static private final class A : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i;} } static private final class B : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i+ 1;} } private immutable I i; private int d; this(int d){ this.d = d; if(d < 10) i = A.instance; else i = B.instance; } int f() { return i.f(d);} } void main(){ import std.stdio; S(1).f().writeln(); /// 1 S(100).f().writeln(); /// 101 } ```