Re: parallel threads stalls until all thread batches are finished.
On 8/28/23 15:37, j...@bloow.edu wrote: > Basically everything is hard coded to use totalCPU's parallel() is a function that dispatches to a default TaskPool object, which uses totalCPUs. It's convenient but as you say, not all problems should use it. In such cases, you would create your own TaskPool object and call .parallel on it: https://youtu.be/dRORNQIB2wA?t=1611s Ali
Re: parallel threads stalls until all thread batches are finished.
On 8/25/23 14:27, j...@bloow.edu wrote: > "A work unit is a set of consecutive elements of range to be processed > by a worker thread between communication with any other thread. The > number of elements processed per work unit is controlled by the > workUnitSize parameter. " > > So the question is how to rebalance these work units? Ok, your question brings me back from summer hibernation. :) This is what I do: - Sort the tasks in decreasing time order; the ones that will take the most time should go first. - Use a work unit size of 1. The longest running task will start first. You can't get better than that. When I print some progress reporting, I see that most of the time N-1 tasks have finished and we are waiting for that one longest running task. Ali "back to sleep"
Re: Bug in usage of associative array: dynamic array with string as a key
On 6/30/23 17:42, Cecil Ward wrote: > https://dlang.org/spec/hash-map.html#testing_membership in the language > docs, under associative arrays - 13.3 testing membership. Would anyone > else care to try that example out as that might be quicker? I tried it by 1) Putting all the code inside a 'void main()' function 2) Pasting the code from the top of that page and it works: void main() { int[string] aa; // Associative array of ints that are // indexed by string keys. // The KeyType is string. aa["hello"] = 3; // set value associated with key "hello" to 3 int value = aa["hello"]; // lookup value from a key assert(value == 3); int* p; p = "hello" in aa; if (p !is null) { *p = 4; // update value associated with key assert(aa["hello"] == 4); } } > the only substantive > change being deleting the variable p Do you mean this: aa.remove("hello"); That works too. D's associative arrays have a few quirks but they work just fine. They are not buggy as it may be inferred from some of the posts here. Ali
Re: Bug in usage of associative array: dynamic array with string as a key
On 6/30/23 13:16, Cecil Ward wrote: On Friday, 30 June 2023 at 19:58:39 UTC, FeepingCreature wrote: Note that you can do `uint ordinal = Decls.ordinals.get(str, -1);`. Is the second argument an ‘else’ then, my friend? Yes, .get and friends appear in this table: https://dlang.org/spec/hash-map.html#properties Ali
Re: Bug in usage of associative array: dynamic array with string as a key
On 6/30/23 12:05, Cecil Ward wrote: > I have code roughly like the following: > > dstring str = "name"d; Aside: One almost never needs dstring. > uint ordinal = (( str in Decls.ordinals ) !is null) ? > Decls.ordinals[ str ] : -1; > > struct Decls > { > uint[ dstring] ordinals; Do you mean 'ordinals' is 'static'? Otherwise, Decls.ordinals does not compile. > } > > //and > Decls.ordinals[ str ] = ordinal_counter++; Are you doing that *after* you initialize 'ordinal' as you show here? :) Ali
Re: is Dlang support Uniform initialization like c++
On 6/30/23 08:18, lili wrote: How too wirte this: addPoint({4,5}, {4,6}) In this case, arrays are better but only if you don't define a constructor, which you don't need for simple types like Point below: struct Point { int x; int y; } void main() { // The type is explicit on the left-hand side Point[] points = [ {1,2} ]; } Ali
Re: pragma msg field name?
On 6/26/23 21:25, Chris Katko wrote: > How do I get just the field name? I know .tupleof, which you can typeof() as well: class myObject{ int field1, field2, field3; static foreach(field; typeof(this).tupleof) { pragma(msg, field.stringof); } static foreach(MemberType; typeof(typeof(this).tupleof)) { pragma(msg, MemberType); } } The output: field1 field2 field3 int int int I had to consult what I wrote years ago: http://ddili.org/ders/d.en/tuples.html#ix_tuples..tupleof Ali
Re: Large statics
On 6/25/23 13:41, Cecil Ward wrote: > The docs say that there is a limit on the size of large statics Customers (at least Weka) did request larger statics in the past. Since they use LDC, the limit was removed for LDC. I did not try it. :) Ali
Re: A couple of questions about arrays and slices
On 6/20/23 19:09, Cecil Ward wrote: > 2.) I have a dynamic array and I wish to preinitialise its alloc cell to > be a certain large size so that I don’t need to reallocate often To be complete, 'assumeSafeAppend' must be mentioned here as well. Without it, there will be cases where the GC cannot guarantee that there are no slices to this particular one; so it has to reallocate: import std; void main() { // An array with room for 100 elements int[] arr; arr.reserve(100); // Take note of current address of the elements auto ptr = arr.ptr; foreach (i; 0 .. 80) { // Add elements arr ~= i; // Was there a reallocation? if (arr.ptr != ptr) { writeln("relocated to ", arr.ptr, " at ", i); ptr = arr.ptr; } // Let's say our algorithm shrinks the array if (i == 50) { arr.length = 0; // assumeSafeAppend(arr); } } } Although the array has room for 100 elements, the program will print something similar to the following: relocated to 7F058B02B000 at 51 relocated to 7F058B02C000 at 54 relocated to 7F058B02D000 at 58 relocated to 7F058B02E000 at 62 relocated to 7F058B02F000 at 66 relocated to 7F058B03 at 74 When it's known that there is no other slice to the old elements, the programmer calls assumeSafeAppend() by uncommenting that line :o). Now there are no relocations. Sweet! Ali
Re: static if - unexpected results
On 6/23/23 07:22, DLearner wrote: >`} else static if (__traits(isPOD, typeof(` ~ VarName ~ `))) {` ~ Regardless, you can also use the 'is' expression with the 'struct' keyword. If T is a struct, is (T == struct) that will produce true at compile time. Ali
Re: How does D’s ‘import’ work?
On 6/20/23 08:09, Cecil Ward wrote: > I’m used to slow compilers on fast machines and compiling > gives me an excuse for more coffee and possibly fruity buns. Yes, all of us in past projects accepted C++'s slowness. We did get coffee, etc. One of my current colleagues regularly plays solitaire when waiting for C++ compilations. Not only it's not a professional sight, but C++ is proving to be a professional mistake. Nobody should suffer from such context switches. I have a hunch, without any backing research data, that C++'s contribution to humanity may be net negative. D is nothing like that: My turnaround is a few seconds: Write, compile, run, see the effect... I use only dmd partly because of laziness: it just works. Although I take full advantage D's low level powers, my programs have mostly been I/O bound with huge files, so dmd's less-than ideal optimization powers are hidden because most threads are waiting for file system I/O. Aside: std.parallelism and std.concurrency have been very helpful. Ali
Re: class Object with Dependency Injection
On 6/18/23 07:37, Salih Dincer wrote: >auto truck = new Truck; >auto ship = new Ship; > >auto services = [ truck, ship ]; The problem is with the deduced type of 'services'. I don't know the mechanism behind it but the common type of 'truck' and 'ship' are deduced to be Object. Apparently, their interfaces don't take part in that decision. I don't know why. One solution is to help the compiler by casting them to your desired interface: auto services = [ cast(ITransport)truck, cast(ITransport)ship ]; Or you can put the casts inside a function that could hide the complexity below: import std.algorithm; import std.range; auto services = [ truck, ship ].map!(s => cast(ITransport)s).array; Ali
Re: Como puedo hacer funciones asincronas?
On 6/17/23 20:20, Cecil Ward wrote: > On Saturday, 17 June 2023 at 22:05:37 UTC, Danico wrote: >> hola gente, quisiera saber como es que puedo hacer funciones asincronas. >> ` >> #!/usr/bin/env dmd >> import std; >> import std.stdio; >> import std.concurrency; >> //import archivo2; >> >> alias print = writeln; >> >> void main () { >> >> auto tarea1 = spawn(&saludo); >> auto tarea2 = spawn(&saludo2); >> >> print("realizando tareas "); >> >> >> } >> >> void saludo () { >> print("hola"); >> } >> >> async saludo2 () { Replace that 'async' with 'void': void saludo2 () { >> print("hola2"); >> } >> >> ` > > This is something I have wanted to achieve also. It just works with that change. std.concurrency appears here in one of my presentations: https://youtu.be/dRORNQIB2wA?t=1735 And some text here: http://ddili.org/ders/d.en/concurrency.html Ali
Re: C++'s this() equivalent?
On 6/15/23 08:15, zjh wrote: > I want `B` to become the following version similar to 'C++'. What should > I do? I have difficulty understanding the question. I think the nested structs, extern(C), static members, etc. confuse me. I am assuming they are not related to this question. > ```cpp > struct B{ > int m; > B(){ Do you want to be able to use the name of the user-defined type to mean "constructor", "destructor", etc? If so, no, it's not possible without preprocessing the text potentially with a C preprocessor. And this is by design: In D, we rename the type and be done with it. In C++, one needs to rename a number of functions as well. Ali
Re: Union with bits ?
On 6/14/23 15:04, Paul wrote: > Question: Why do you say "may be slower than necessary"? Do you mean > compile or runtime or both? Definitely at compile time because the string that gets mixed-in first needs to be generated from your specification. For that, the bitfields() function must be compiled and executed at compile-time. Then the mixed-in code will be compiled. I remember reading here about lackluster compilation performance in that area. And it may be slow at run time as well depending on certain checks the functions perform. For example, you will notice that setting the value 2 will fail at run time on a 1-bit member. If you would never pass a 2 value for such a function, than it may be seen as extra cost. By the way, the string that bitfields() generates can be visualized by simply printing it: const code = bitfields!( ubyte, "A", 1, ubyte, "B", 1, ubyte, "C", 1, ubyte, "padding", 5,); writeln(code); The output is not pretty for the human eye but those are basically the getters and setters that Adam D Ruppe mentioned. Ali
Re: Union with bits ?
On 6/13/23 17:59, Paul wrote: > I would like to have labeled bits in a union with a ubyte. Something > like this: > ```d > struct MyStruct { > union { > ubyte status; > bit A, B, C…etc > } > } > ``` > Is something like this possible? > > Thanks D's string mixin syntax may not be the best, the implementation may be slower than necessary, and the concept may be strange (not macros but very similar) but I still find phobos's bifields to be brilliant. https://dlang.org/phobos/std_bitmanip.html#bitfields import std.bitmanip; struct MyStruct { union { ubyte status; mixin(bitfields!( ubyte, "A", 1, ubyte, "B", 1, ubyte, "C", 1, ubyte, "padding", 5,)); } } void main() { auto m = MyStruct(); m.B = 1; assert(m.status == 2); } Ali
Re: byte and short data types use cases
On 6/9/23 08:07, Murloc wrote: > Where can I read more about this? I had written something related: http://ddili.org/ders/d.en/memory.html#ix_memory..offsetof The .offsetof appears at that point. The printObjectLayout() function example there attempts to visualize the layout of the members of a struct. Ali
Re: How does D’s ‘import’ work?
On 6/7/23 21:17, Cecil Ward wrote: > I was thinking about the situation in C where I have a rule in a make > file that lists the .h files as well as the .c all as dependencies in > creating an object file. dmd's -makedeps command line switch should be helpful there. (I did not use it.) Ali
Re: How do I generate `setX` methods for all private mutable variables in a class?
On 6/6/23 09:13, Basile B. wrote: > yeah I know that opDispatch is disliked because it is tried in a SFINAE > fashion, as citicized by Adam. But on the other side it's the best opover. I like how it helped in my current project: user.someShellCommand("-foo", "-bar"); opDispatch makes a command string, passes it to executeShell, takes care of the return code and dumps its output if there was an error. Ali
Re: Code duplication where you wish to have a routine called with either immutable or mutable arguments
On 5/29/23 19:57, Cecil Ward wrote: > I wish to have one routine > that can be called with either immutable or (possibly) mutable argument > values. 'const' should take both immutable and mutable. Can you show your case with a short example? > Could I make the one routine into a template? That could work but give 'in' parameters a try: https://dlang.org/spec/function.html#in-params Ali
Re: How can I use Linker flags using DMD?
On 5/29/23 17:39, Marcone wrote: > Can you help me static link dll msvcr120.dll in my x64 dlang program? Sorry, I haven't been programming on Windows for a very long time now. :/ But there are others who program on Windows here. Ali
Re: How can I use Linker flags using DMD?
On 5/29/23 07:29, Marcone wrote: I want send flags to linker when using dmd.exe compiler. -L does it. Yes, -L-L can happen. :) https://dlang.org/dmd-linux.html Ali
Re: Lockstep iteration in parallel: Error: cannot have parameter of type `void`
On 5/20/23 04:21, kdevel wrote: > Thanks for your explications! > > On Friday, 19 May 2023 at 21:18:28 UTC, Ali Çehreli wrote: >> [...] >> - std.range.zip can be used instead but it does not provide 'ref' >> access to its elements. > > How/why does sort [1] work with zipped arrays? I don't know but wholesale assignment to zip's elements do transfer the effect, which sort does while swapping elements. However, copies of those range elements do not carry that effect: import std; void main() { auto a = [ 0, 1 ]; auto z = zip(a); z[0] = z[1]; writeln("worked: ", a); zip(a).each!(e => e = 42); writeln(" nope: ", a); } And each does not take (ref e) as a parameter at least in that use case. >> The following amap example there may be useful for your case but I >> could not make the types work: > > Do you mean using the function pointer does not work? I simply copied the example code bet there were mismatches between float, real, etc. And I've just discovered something. Which one of the following is the expected documentation? https://dlang.org/library/std/parallelism.html https://dlang.org/phobos/std_parallelism.html What paths did I take to get to those? I hope I will soon be motivated enough to fix such quality issues. Ali
Re: Lockstep iteration in parallel: Error: cannot have parameter of type `void`
On 5/19/23 02:17, kdevel wrote: Should this compile? dmd says Multiple points: - lockstep works only with foreach loops but it's not a range. - std.range.zip can be used instead but it does not provide 'ref' access to its elements. - However, since slices are already references to groups of elements, you don't need 'ref' anyway. - You seem to want to assign to elements in parallel; such functionality already exists in std.parallelism. - Phobos documentation is not very useful these days as it's not clear from the following page that there are goodies like amap, asyncBuf, etc. It just shows parallel() and a few friends at the top: https://dlang.org/phobos/std_parallelism.html One needs to know to click TaskPool: https://dlang.org/phobos/std_parallelism.html#.TaskPool The following amap example there may be useful for your case but I could not make the types work: // Same thing, but explicitly allocate an array // to return the results in. The element type // of the array may be either the exact type // returned by functions or an implicit conversion // target. auto squareRoots = new float[numbers.length]; taskPool.amap!sqrt(numbers, squareRoots); // Multiple functions, explicit output range, and // explicit work unit size. auto results = new Tuple!(float, real)[numbers.length]; taskPool.amap!(sqrt, log)(numbers, 100, results); https://dlang.org/phobos/std_parallelism.html#.TaskPool.amap Ali
Re: Proper way to handle "alias this" deprecation for classes
On 5/7/23 13:44, Chris Piker wrote: > to fix the problem I > just delete the alias this line from dpq2, see what unit tests and app > code it breaks, then fix each of those. Yes but I neglected the lvalue/rvalue issue. In some cases the code won't compile if the return type of the newly written explicit function is not 'ref'. For example, the 'ref' below is essential for the following use case: class C { int* result; // HERE ref asIntPtr() { return result; } } auto main() { auto c = new C(); int i; c.asIntPtr = &i; assert(c.result == &i); } > "Programming in D" for a bright young programming > student I know in appreciation. Very kind of you! :) Ali
Re: Proper way to handle "alias this" deprecation for classes
On 5/7/23 10:55, Chris Piker wrote: > According to dmd 2.103, alias this is > deprecated for classes, so I'd like to correct the problem. alias this is for implicit type conversions, which can be achieved explicitly as well. Given the following old code: class C { int* result; alias result this; } void foo(int*) { } auto main() { auto c = new C(); // Implicit type conversion from C to int*: foo(c); } One can use a member function instead: class C { int* result; auto asIntPtr() { return result; } } void foo(int*) { } auto main() { auto c = new C(); // The same type conversion is now explicit: foo(c.asIntPtr); } Ali
Re: A Programmer's Dilema: juggling with C, BetterC, D, Macros and Cross Compiling, etc.
On 5/1/23 03:23, Mike Parker wrote: > If you're referring to `rt_init` and `rt_term` are the `extern(C)` > functions in `core.runtime`. It's not necessary to call those from C. A > D library with a C interface can provide an `extern(C)` initialization > function that internally calls `Runtime.initialize`. Indeed. That appears at the following spot of one of my DConf presentations, which touches on several points relevant to writing a C library in D: https://youtu.be/FNL-CPX4EuM?t=2585 Ali
Re: Cannot get this C++ example migrated to D
On 4/16/23 00:46, Skippy wrote: > I wish D had value type classes as well. That cannot work due to the slicing problem. C++ cannot have value type classes either for the same reason. The difference there is that the enforcement is by guidelines (e.g. "never pass class objects by value to functions", not by language). If you want class objects on the stack, you have two options: - The scope keyword - The scoped template from Phobos Ali
Re: class variable initialization
On 4/15/23 09:06, NonNull wrote: >> struct Wrapper >> { >>Object x = new Object(); >>alias x this; >> } > Amazing, was this always so? At least for a long time. However, every Wrapper object will have a pointer to that single shared object. If you think that cost is unnecessary, you can have a static variable: struct Wrapper { static Object x; alias x this; } static this() { Wrapper.x = new Object(); } However, because such data are thread-local by-default, not the entire class, but each thread will have a copy that variable. When you want a single class variable for all threads, then it must be defined as shared: struct Wrapper { shared static Object x; alias x this; } shared static this() { Wrapper.x = new Object(); } void foo(shared Object o) { assert(o !is null); } Note how foo's interface had to be changed as well. And of course you may have to provide thread synchronization when that variable needs to be mutated at run time. Ali
Re: Memory leak issue between extern (c) and D function
On 4/13/23 20:50, backtrack wrote: > mystruct* getmystruct() > { > mystruct* mystruct = cast(mystruct*)malloc(mystruct.sizeof); > return mystruct; > > } There must be a corresponding function to do the cleaning: void freemystruct(mystruct* ptr) { free ptr; } You have to make sure on the D side that freemystruct() is called once for each getmystruct(). I have the following presentation that covers similar concepts: https://www.youtube.com/watch?v=FNL-CPX4EuM I think this point is most relevant: https://www.youtube.com/watch?v=FNL-CPX4EuM&t=1833s Ali
Re: Assocative array lookup for object
On 4/12/23 04:35, Salih Dincer wrote: > I made a little mistake and I'll fix it before someone rub nose in it :) You asked for it! :) >auto opIndex(string key) { > if(auto ret = key in data) > { >return *ret; > } > return null; >} Not every type is null'able but nullable. ;) So, a design may use the following: https://dlang.org/library/std/typecons/nullable.html Ali
Re: How come a count of a range becomes 0 before a foreach?
On 4/8/23 21:38, ikelaiah wrote: > I will modify the code to construct it twice. Multiple iterations of dirEntries can produce different results, which may or may not be what your program will be happy with. Sticking an .array at the end will iterate a single time and maintain the list forever because .array returns an array. :) auto entries = dirEntries(/* ... */).array; Ali
Re: DlangUI Layout Justification
On 3/9/23 07:09, Ron Tarrant wrote: Many thanks, ryuukk. I'll check it out. I don't know how relevant it is but there is also Hipreme Engine that supports Android: https://forum.dlang.org/thread/fecijdotstuclyzzc...@forum.dlang.org Ali
Re: Code organization, dub, etc.
On 3/13/23 07:30, Joe wrote: > whether DLang (the Foundation and/or the > community) would consider working with the CMake and clang-format > communities to get them to support D in their products That would be great. I hope it will eventually happen. I've used CMake on existing projects only as a tool that is better than some others. Witnessing CMake being replaced by even better tools like Bazel, should CMake be a target or should Bazel, etc. take precedence? Ali
Re: member func is best choice for pointers?
On 4/6/23 07:26, a11e99z wrote: > ```d > import std, core.lifetime; > > struct Node { > Node* pNext; > void func() { "Node::func %s".writeln( pNext); } That's a member function, which works with the obj.func() syntax. However, there is another feature of D that is in play here: Members can directly be accessed through pointers without dereferencing. pn.func() has the same effect as (*pn).func() (That's why D does not use C's -> operator). > } > void func( Node* p ) { "::func %s(%s)".writeln( p, p == null ? p : > p.next); } Ok, that function can be called normally as func(pn) or with UFCS as pn.func() However, UFCS takes place only when there is no such member. I understand how this can be surprising but it is still within spec: There does exist a member with the name 'func', so UFCS is not applied. One can rightly argue that automatic pointer dereferencing should take place after UFCS consideration but apparently that's not the case. If that were the case, I suspect there would be other programmers who would be looking for the current behavior. Ali
Re: regex matching but not capturing
On 4/6/23 11:08, Paul wrote: ways to access those repetitive ", cc" s on the end. I don't think my regex is capturing them. Some internets think you are in parser territory: https://stackoverflow.com/questions/1407435/how-do-i-regex-match-with-grouping-with-unknown-number-of-groups Ali
Re: Virtual method call from constructor
On 4/4/23 00:08, Chris Katko wrote: > dscanner reports this as a warning: > > ```D > struct foo{ > this() >{ >/* some initial setup */ >refresh(); >} > void refresh() { /* setup some more stuff */} > // [warn] a virtual call inside a constructor may lead to unexpected > results in the derived classes > > } > ``` I can understand that error for a class. Is that really a struct? If so, then it looks like a dscanner bug to me. > Firstly, are all calls virtual in a struct/class in D? All functions are by-default virtual only for classes. To note, not the "call" but the function can be virtual. When calls are involved, there can be static binding and dynamic binding. Static binding is when a call is resolved at compile time. Dynamic binding is resolved at run time through the vtbl pointer. > Is this any > different from C++? Yes. In C++, all functions are non-virtual by-default. > IIRC, in C++, a struct cannot have virtual calls, No, structs and classes are functionally exactly the same in C++. The only difference is their default member accessibility: public for structs and private for classes. > and virtual methods are explicit keywords in classes. Yes. > Second, could you give me some case examples where this problem occurs? > Is the issue if I override refresh in a derived class, and the base > class will accidentally use child.refresh()? Yes. :) Here is what I had learned in my C++ days: The vtbl pointer is stamped before the constructor is entered. However, an object is not yet complete without its constructor exiting. The base class's constructor calling a virtual function of its derived part might be disastrous because the derived part is not fully constructed yet. (Well, it is not as disastrous in D because all members have default values by-default.) import std; class Base { void foo() { writeln(__FUNCTION__); } this(int i) { writeln("Entered ", __FUNCTION__); foo(); // <-- THE PROBLEM writeln("Exiting ", __FUNCTION__); } } class Derived : Base { override void foo() { writeln(__FUNCTION__); } this(int i) { writeln("Entered ", __FUNCTION__); super(i); writeln("Exiting ", __FUNCTION__); } } void main() { auto d = new Derived(42); } Here is the (annotated) output: Entered deneme.Derived.this Entered deneme.Base.this deneme.Derived.foo<-- NO! Exiting deneme.Base.this Exiting deneme.Derived.this The highlighted line is a call to a derived function but even the base part of the object is not finished its construction yet. The weird thing is Base is initiating the call but it has no idea even whether it's a part of an inheritance hierarchy, what other types are involved, etc. Ali
Re: foreach (i; taskPool.parallel(0..2_000_000)
On 4/4/23 02:24, Salih Dincer wrote: > I don't understand what `foreach()` does :) Hm. I forgot whether 'parallel' works only with 'foreach'. But there are various other algorithms in std.parallelism that may be more useful with range algorithm chains: https://dlang.org/phobos/std_parallelism.html > in Turkish I don't have time to experiment more at this time but I have the following chapters, which includes some of those other algorithms as well: http://ddili.org/ders/d/kosut_islemler.html http://ddili.org/ders/d.en/parallelism.html Ali
Re: foreach (i; taskPool.parallel(0..2_000_000)
On 4/1/23 15:30, Paul wrote: > Is there a way to verify that it split up the work in to tasks/threads > ...? It is hard to see the difference unless there is actual work in the loop that takes time. You can add a Thread.sleep call. (Commented-out in the following program.) Another option is to monitor a task manager like 'top' on unix based systems. It should multiple threads for the same program. However, I will do something unspeakably wrong and take advantage of undefined behavior below. :) Since iteration count is an even number, the 'sum' variable should come out as 0 in the end. With .parallel it doesn't because multiple threads are stepping on each other's toes (values): import std; void main() { long sum; foreach(i; iota(0, 2_000_000).parallel) { // import core.thread; // Thread.sleep(1.msecs); if (i % 2) { ++sum; } else { --sum; } } if (sum == 0) { writeln("We highly likely worked serially."); } else { writefln!"We highly likely worked in parallel because %s != 0."(sum); } } If you remove .parallel, 'sum' will always be 0. Ali
Re: Why are globals set to tls by default? and why is fast code ugly by default?
On 3/26/23 13:41, ryuukk_ wrote: > C, C++, Rust, Zig, Go doesn't do TLS by default for example C doesn't do because there was no such concept when it was conceived. C++ doesn't do because they built on top of C. (D does because it has always been innovative.) Go doesn't do because it had no innovations anyway. Does anyone have documentation on why Rust and Zip does not do thread local by default? I wonder what experience it was based on. Speaking of experience, I used to be a C++ programmer. We made use of thread-local storage precisely zero times. I think it's because the luminaries of the time did not even talk about it. With D, I take good advantage of thread-local storage. Interestingly, I do that *only* for fast code. void foo(int arg) { static int[] workArea; if (workArea.length < nededFor(arg)) { // increase length } // Use workArea } Now I can use any number of threads using foo and they will have their independent work areas. Work area grows in amortized fashion for each thread. I find the code above to be clean and beautiful. It is very fast because there are no synchronization primitives needed because no work area is shared between threads. Finding one example to the contrary does not make TLS a bad idea. Engineering is full of compromises. I agree with D's TLS by-default idea. Since I am here, I want to touch on something that may give the wrong idea to newer D programmers: D does not have globals. Every symbol belongs to a module. And copying an earlier comment of yours: > It's common knowledge that accessing tls global is slow > http://david-grs.github.io/tls_performance_overhead_cost_linux/ "TLS global is slow" would be misleading because even the article you linked explains right at the top, in the TL;DR are that "TLS may be slow". Ali
Re: The Phobos Put
On 3/29/23 12:21, ag0aep6g wrote: > As far as I understand, you're saying that we cannot overload on `ref`. > But we can. Salih's code demonstrates just that. > > void f(ref int x) {} > void f(int x) {} > void main() { int x; f(x); f(42); } /* no errors */ I thought Salih was proposing two more overloads to the existing put(). When I copy the existing put(), which takes 'ref R', not R[], then the code does not compile: auto put(R)(R[] range, R[] source) => putImpl(range, source); auto put(R)(ref R[] range, R[] source) => putImpl(range, source); void putImpl(R)(ref R[] range, R[] source) { assert(source.length <= range.length); foreach(element; source) { range[0] = element; // range.front() range = range[1..$]; // range.popFront() } } void put(R, E)(ref R r, E e) { // This is from Phobos <--- } void main() { enum data = [1, 0, 0, 4]; auto arr = data; auto slice = arr[1..$-1]; slice.put([2]); // <-- ERROR assert(arr == [1, 2, 0, 4]); slice.put([3]); assert(arr == [1, 2, 3, 4]); arr[1..$-1].put([0, 0]); assert(arr == data); } Ali
Re: The Phobos Put
On 3/29/23 09:27, Salih Dincer wrote: > In this way, > it could also be used directly with slices. For example: > auto put(R)(R[] range, R[] source) >=> putImpl(range, source); That's for rvalues. > auto put(R)(ref R[] range, R[] source) >=> putImpl(range, source); That's for lvalues. If you are proposing keeping the current ref-taking Phobos put() as well, then the following call would be ambiguous: slice.put([2]); // Compilation ERROR That can be remedied by using template constraints for 'slices' vs. other output ranges. But that would be against the idea of "D slices are most capable ranges". What I mean is, I should be able to write any range algorithm and pass a slice to it and it should work. If we go with your proposal, then we would have to check for that case for some algorithms like put(). Further, I think the user of put() in templates would have to check whether they are dealing with a slice or not: void foo(R)(R range) { range.put(/* ... */); // If we go with your proposal, whether 'range' changed depends // on whether R is a slice or not. Do we have to check with // 'static if' in such range algorithms? } Note that I am not defending the behavior of put(). I am just trying to explain why it is so. Ali
Re: The Phobos Put
On 3/29/23 04:48, Dennis wrote: > On Wednesday, 29 March 2023 at 11:10:42 UTC, Salih Dincer wrote: >> Why does my `put` work but the Phobos `put` doesn't work with a slice? > > Your `put` doesn't take `range` by `ref`, so it allows you to pass an > rvalue. Consequently, it doesn't advance the range from the callers > perspective. And that 'ref' is necessary because not every OutputRange can be sliced for further calls to put(). Salih does not have that problem because he is working with slices, which are (usually) trivially slicable for the next portion to be passed to put(). On the other hand, Phobos's put() works with any OutputRange so it has to take a 'ref' to advance to know where it is left off. This behavior makes its use with slices weird but sometimes such is life. :) Ali
Re: Calling assumeSorted on const(std.container.Array)
On 3/25/23 09:31, Olivier Prat wrote: On Saturday, 25 March 2023 at 13:45:36 UTC, Olivier Prat wrote: I'm trying to call assumeSorted on a const(Array) using this code snippet: [...] In a similar fashion, a number of methods in SortedRange do not compile if called on a const(SortedRange) or immutable(SortedRange), such as length, or front. Is this on purpose? There are a number of interesting points in your original post but I couldn't find time to answer all of those. I can inject this for now: :) assumeSorted returns a range object. The concept of a const range object is flawed because by nature iteration of a range happens by mutating it: For example, popBack has to do that. So, it's normal that any range algorithm will assume a non-const object. Ali
Re: Segfault with std.variant
On 3/24/23 23:07, Mitchell wrote: >variant["four"] = Variant(4); // Segfault Today I learned that VariantN forwards to associative array operations. Cool I guess. :) > with a segfault. I'm using LDC2: Same with dmd. It fails in the destructor of VariantN. static if (!AllowedTypes.length || anySatisfy!(hasElaborateDestructor, AllowedTypes)) { ~this() { // Infer the safety of the provided types static if (AllowedTypes.length) { if (0) { AllowedTypes var; } } (() @trusted => fptr(OpID.destruct, &store, null))(); } } That @trusted lambda call segfaults. This looks like a bug to me. Reported: https://issues.dlang.org/show_bug.cgi?id=23809 Ali
Re: Implicit type conversion depending on assignment
On 3/23/23 07:36, Alexander Zhirov wrote: > @property auto toString(T)() The name is misleading because you want types other than string as well. > alias toString this; That should have been a compilation error because 'toString' does not have a known type (because it depends on a template parameter). How can the compiler accept that 'alias this'? > int myInt = a; > float myFloat = b; Since you need to spell out 'int' and 'float' in some form anyway, the following would be my choice, which I did use in my code before: struct MyVal { private string value; auto to(T)() { import std.conv : to; return value.to!T; } } void main() { auto a = MyVal("100"); auto b = MyVal("11.2"); auto myInt = a.to!int; auto myFloat = b.to!float; } Should it be an error to convert 'a' to float? If so, the following modules may be helpful: https://dlang.org/phobos/std_sumtype.html https://dlang.org/phobos/std_variant.html Ali
Re: Implicit type conversion depending on assignment
On 3/23/23 06:38, Alexander Zhirov wrote: > Is it possible to convert such records inside the structure to the > assigned type? D does not embrace implicit conversions. There is some support like 'alias this' as you mentioned but what you are looking for is not possible. Ali
Re: Threads
On 3/21/23 22:30, Tim wrote: > to make a simple multi-threading application. Unless there is a reason not to, I recommend std.concurrency and std.parallelism modules. They are different but much more simpler compared to the low-level core.thread. > args_copy = args; //Why program name is missing while copy arguments? That doesn't copy. Both args_copy and args will be references to the same elements. (They are both array slices.) The following may work to get a shared argument: immutable args_copy = args.idup; idup makes an immutable copy and immutable is implicitly shared. Even if that works, I still find std.concurrency much easier to deal with. :) Ali
Re: alias Error: need 'this'
On 3/19/23 06:49, bomat wrote: > I can live with the `static` > solution, I guess. If you could, you would define it 'static' anyway. :) Because you highly likely needed a distinct 'variableWithALongName' member for each MyStruct object, that wouldn't work. > Shouldn't it be the exact same underlying mechanism? I don't know the answer. Luckily, what you describe is available in another form in the language: ref alias2() { return myStruct.memberWithALongName; } Ali Unrelated: I find 'myObject' a more correct name for a variable because if 'struct' is the definition of a type, 'myStruct' attempts to convey a misleading meaning.
Re: const in functions
On 3/12/23 16:14, FozzieBear wrote: > On Sunday, 12 March 2023 at 15:09:45 UTC, Salih Dincer wrote: >> >> ... > > So I don't agree with part of this comment (made elsewhere in this thread): > > "You can live without 'const' until your code interacts with other > people's code." My comment was purely technical. What I meant is, if the code is an island where there is no single 'const' in sight, then a D programmer can live by ignoring 'const'. At a technical level... This is different from C++ where you have to use references to const in order to take rvalue references as parameters. Since D does not allow binding rvalues even to references to const, this is a moot point. (-preview=in does bind rvalues to references as an optimization but that fact is hidden from the programmer.) So, my comment is correct at a technical level. > Code interacts with other code. Code should always be clear as to its > intent. Absolutely. That's why I always start with 'const' (what should have been the default but is not for historical reasons): const foo = bar(); I change that 'const' to e.g. 'auto' as needed. > Who wrote that code, or other code that interacts with that > code, is irrelvant. However, there is always the danger of going too far though. To keep the fun in the game, a programmer should be free to do whatever they want in their own code e.g. in their throw-away script programs. Here is one line I never include in production code but I very frequently use in short programs: import std; Removes mental load, frees the mind, and enables flow of programming. Some code is written for myself, not for people who are not watching over my shoulder. There is pride in caring for every character of the source code but sometimes freedom from all concerns is good too. Luckily, D makes it easy to refactor as requirements change. Ali
Re: const in functions
On 3/13/23 08:17, Salih Dincer wrote: > In this case, using `ref` will increase performance while reducing the > number of copies. I am not sure about that. Unless there is an expensive copy construction, most objects are simple data copies. To use 'ref' or not should be guided through semantics. Luckily, we have the -preview=in command line switch that removes the cost of copying from the equation: https://dlang.org/spec/function.html#in-params Just marking the input parameters 'in' should be sufficient in most cases. Ali
Re: 'auto' keyword
On 3/12/23 06:07, DLearner wrote: > 1. As a shorthand to make the type of the variable being declared the > same as the type on the right hand side of an initial assignment. As Adam explained, D already has type inference without a special keyword. However, some places where 'auto' (or 'const', etc.) appear is not only for "shorthand" but for necessity. Some types cannot be spelled-out at all: auto foo() { struct S {} return S(); } void main() { pragma(msg, typeof(foo())); auto s = foo(); } The name 'S' is available only inside 'foo', so code outside has no choice but to use 'auto' (or 'const', etc.) Having said that, it is still possible to alias the returned type, which may be cumbersome in some cases because you may have to come up with a clean expression for attempting to call the function. In this case it's trivial because foo does not take any parameter: alias T = typeof(foo()); T t;// <-- There: I did not need to use 'auto' Ali
Re: const in functions
On 3/12/23 08:09, Salih Dincer wrote: > As someone who has used const very little in my life You can live without 'const' until your code interacts with other people's code. For example, the following program works just fine: struct S { int * p; void foo() {} } void bar(S s) {} void main() { auto s = S(); s.foo(); bar(s); } Now you replace (or a user of your code replaces) 'auto' with 'const' and you will get 2 compilation errors: const s = S(); s.foo();// ERROR 1 bar(s); // ERROR 2 So, if your code will ever interact with other people's code it must be const-correct. If foo() is not mutating the object (including through the p member), it better be defined as 'const': void foo() const {} And if bar() is not mutating the parameter, it better take as const: void bar(const(S) s) {} Now the code compiles. You can (and should) use 'const' everywhere that you can because it increases the usability of code: Mutable, 'const', and 'immutable' variables can be used with code that takes by 'const'. This is not the same with code taking by 'immutable'. It can only be used with 'immutable' variables. Ali
Re: How to expand wildchar under dos ?
On 3/9/23 19:24, John Xu wrote: > Under dos, how to get wildchar matched file names? Have you tried dirEntries? It supports glob patterns: https://dlang.org/library/std/file/dir_entries.html Ali
Re: Passing and returning arguments by ref
On 3/3/23 12:45, Joe wrote: > I had tried changing B.x1() to: > >`ref X x1() { return &xs[0]; }` > > but the compiler didn't accept it. Yeah, that wouldn't work because the return expression is an X*. Even though 'ref' is implemented as a pointer behind the scenes, that syntax is not legal. > It's a bit weird that by taking the address of calling B.x1() and thus > getting an X* Agreed but that's how it is. Taking the address of a reference produces an X*. > I had to *dereference* that to pass it to the helper > function of A.mfd() which actually takes a `ref C` argument. Yep, all of that makes sense. :) Ali
Re: Passing and returning arguments by ref
On 3/3/23 06:03, Joe wrote: > My understanding was that since A, B and X[] are all reference types, > this ought to work, but obviously something is missing. Think may be due to D not having reference variables. Sometimes one needs to use pointers. I find the following a simpler (and complete ;) ) example. foo() returns by ref and indeed, the change made to its return value is visible in main. However, the same foo() is later called to initialize hopefullyRef but not the change made to that variables is not reflected in the array. (By the way, the example could be written without an array as well.) struct S { int i; void change() { ++i; } } ref S foo(S[] arr) { return arr[0]; } void main() { auto arr = [ S(1) ]; // Ok, this operation changes arr[0] foo(arr).change(); assert(arr[0].i == 2); // This one changes the local variable auto hopefullyRef = foo(arr); hopefullyRef.change(); assert(hopefullyRef.i == 3); // The array is still 2 assert(arr[0].i == 2); } hopefullyRef in just an int. The following definition of the hopefullyRef variable would cause the array element be changed: // Now an S* (note & on the rigth-hand side) auto hopefullyRef = &foo(arr); // Now hopefullyRef is an S*, not an S // Same as before hopefullyRef.change(); assert(hopefullyRef.i == 3); // Now the array is affected (3, not 2) assert(arr[0].i == 3); Ali
Re: Bug in DMD?
On 3/2/23 15:34, ryuukk_ wrote: > the problem is not that it can run in the background, the problem is > figuring out > > 1. how to install > 2. how to setup > 3. how to run I haven't used it myself but dustmite seems to be integrated into dub. 'dub dustmite <...>' Ali
Re: Deciding one member of iteration chain at runtime
On 2/17/23 09:30, Chris Piker wrote: > operatorG needs > to be of one of two different types at runtime std.range.choose may be useful but I think it requires creating two variables like g1 and g2 below: import std.range; import std.algorithm; void main(string[] args) { const condition = (args.length > 1); // The first part of the algorithm auto r = iota(10) .filter!(n => n % 2); // Two different steps auto g1 = r.map!((int n) => n * n); auto g2 = r.map!((int n) => n * 10); // The rest of the algoritm auto result = choose(condition, g1, g2) .array; } Ali
Re: Gneric linkedList range adaptor
On 2/10/23 14:10, Ben Jones wrote: > Any idea how to fix the helper method? I came up with the following solution: > struct LinkedListAdaptor(alias nextField, T){ In this case nextField will be a callable (a lambda below). > void popFront() { > current = __traits(child, current, nextField); I changed that to current = nextField(current); > auto rng1 = LinkedListAdaptor!(Node.next, Node*)(head); Commented that out. > auto rng = linkedListAdaptor!(Node.next)(head); Replaced that with auto rng = linkedListAdaptor!(node => node.next)(head); Now it works but explicitly creating a lambda feels less than ideal. Perhaps it can be improved. Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/9/23 15:59, ProtectAndHide wrote: > some 'key D > people' (wink wink) [...] > So I hand that over to you .. wink wink. You're trolling[1] again. Ali [1] https://www.merriam-webster.com/dictionary/troll#h3
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/9/23 15:58, thebluepandabear wrote: >> In contrast, I use D every day and love its relaxed attitude towards >> private. > > the fact that private stuff is accessible from other classes in the same > module is really really bad, and it's pretty detrimental to the language. Not everybody shares that view. So, there must be something deeper here: maybe some people are blind (including me), or others have expectations that they carry from other languages, or something else... But look at the contrast: Some people see the same thing as great and some people see it as really really bad. One thing is clear: We can't agree on this topic at least at this time. > let's actually think about what `private` means. It gives implementation freedom: I can change my implementation at will. The same exact goal can be achieved by convention as well: I can name my members with e.g. an underscore and everybody understands that they are private. Nobody touches it and they are protected from future implementation changes. If they do, they do it with full understanding that their code may break in the future. > when you come back from work, arrive home, and you close the curtains > and want some alone, you want to be private to everyone. I don't agree with that example: Yes, it's the same word but different meanings in code. > you wouldn't want your neighbours (the module) to peek at what you're > doing. Yes but I would have no problem other code looking at or using parts of my code if they wanted to. > your neighbours aren't your friends in real life, There is some friendship with my neighbors! :) > and they (the module) > aren't your friends in code Some of them are and some aren't. > -- just because they are in your vicinity > doesn't mean they have a right to violate your privacy. Right to violate doesn't mean anything will be broken. It means, there will be no hurdle if access is needed. Nobody will or does violate anything. I haven't seen a single time when D's approach to privacy caused harm. > tbh this whole private behaviour should be changed, it's just so weird Ok, I like "so weird" more than "really really bad". :) Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/9/23 14:34, ProtectAndHide wrote: > You mentioned previously that D implements various things in > unprincipled ways. I think you will continue misunderstanding that term. What it means is, D does not insist on certain programming paradigms over others. For example, you can code in structured, functional, object-oriented, etc. styles depending on your problem. > I guess, if one wants to use D, one has to be comfortable with this. I can't see how being free is something that one needs to be comfortable with but I guess you are correct. > But using a relaxed attitude towards the implementation of such a common > and important abstraction, that in turn allows me to so easily shoot > myself in the foot, is not really an attractive feature .. to me ;-) Thanks for the wink. > btw. When a newbie to D raises ideas, suggestions, etc... and you > counter them with (in essence) That is not the essence at all! There has been numerous responses here before I reminded how the path is actually open for language changes. > 'we don't need that in D, but go write a > dip if you think we do' attitude, is a real turn off. What was the alternative? Jumping to implementations of all suggested features? A bigger turn off would be forkit! Ali
Re: staticMap but with two arguments
On 2/9/23 12:45, John Chapman wrote: > On Thursday, 9 February 2023 at 19:17:55 UTC, Ali Çehreli wrote: >> I could not figure out eliminating the hard-coded 4. Can we introspect >> the parameter list of a template like 'fun' in the example? If we >> could, then we could get 4 that way. > > Thank you for this. I don't mind hard-coding the N argument. > TemplateArgsOf needs an instantiated template but maybe ```enum N = > count(fun.stringof, ',') + 1``` is good enough. Hopefully but very fragile: template t(int[] T = [ 1, 2 ]) {} void main() { import std.algorithm : count; enum N = count(t.stringof, ',') + 1; static assert(N == 1); // FAILS } Same thing with any other thing with comma in it e.g. template t(T = anotherTemplate!(1, 2)) {} Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/8/23 04:07, zjh wrote: > Last time, someone proposed to add `private` like `C++'s`, We've discussed the 'private' topic very many times already. C++'s private necessitate the 'friend' keyword, which comes with it's own problems. Besides, D has zero problems with its private implementation in the sense that there has been zero bugs related to it being that way. Given the number of individuals who bring this topic up over and over up is so few that I don't think there is a common problem. Do you have actual bugs related to this? "Wanting" the inclusion of a feature is sufficient. In contrast, I use D every day and love its relaxed attitude towards private. > and then it > was the same,they are always unwilling to add facilities useful That is not correct. The truth is, nobody is jumping to implementations just because some people think they are useful. There are always valid reasons for including a feature or not. Ali
Re: Sort Associative Array by Key
On 2/8/23 23:19, Alexander Zhirov wrote: >> foo.byPair >> .array >> .sort!((a, b) => a.key < b.key) >> .map!(a => a.value); > > Is it possible to specify in `map` to return the result `[a.key] = > a.value`? To make the result look like `[key:[val], key:[val]]` map can return a tuple and std.array.assocArray can make an associative array from those tuples: import std; void main() { auto aa = iota(10) .map!(n => tuple(n, n * n)) .assocArray; writeln("Necessarily unsorted:\n", aa); } However, as the original question started with an associative array anyway, I don't think I understand your question correctly. :) If you are asking whether an associative array can store in sorted key order, then no, it's impossible because associative arrays are hash tables, which can't provide that. But we can visit the elements in sorted order if we sort those keys ourselves: auto keys = aa .keys // <- Makes an array by copying the keys .sort; writeln("In order:"); foreach (k; keys) { writeln(k, ": ", aa[k]); } Ali
Re: How to debug/set breakpoint a dynamic library.so ?
On 2/9/23 06:00, mw wrote: The dynamic library.so is built from D (with pyd), and invoked from Python. I'm just wondering How to debug/set breakpoint a dynamic library.so ? Can someone give an example? Thanks. I may be totally off on this but I think it is as simple as the following: gdb --args your_python_program Once inside, set a break point on the dynamic library symbol. Then run. Ali
Re: staticMap but with two arguments
On 2/8/23 12:04, John Chapman wrote: > rather than write it manually for each N? import std.meta : AliasSeq; template pickArgs(size_t totalElements, size_t argsPerElement, size_t whichElement, args...) { alias pickArgs = AliasSeq!(); static foreach (a; 0 .. argsPerElement) { pickArgs = AliasSeq!(pickArgs, args[whichElement + a * totalElements]); } } template staticMapN(size_t N, alias fun, args...) { static assert(N != 0, "N must be non-zero."); static assert((args.length % N) == 0, "Mismatched number of arguments"); enum totalElements = args.length / N; alias staticMapN = AliasSeq!(); static foreach (e; 0 .. totalElements) { staticMapN = AliasSeq!(staticMapN, fun!(pickArgs!(totalElements, N, e, args))); } } // An example struct with some template parameters struct S(T, size_t length, size_t foo, size_t bar) { } // An example template that creates instantiations of the S template template Instantiate(T, size_t length, size_t foo, size_t bar) { alias Instantiate = S!(T, length, foo, bar); } // Compile-time argument sets for three instantiations of the S template alias myTypes = AliasSeq!(int, double, long); alias mySizes = AliasSeq!(1, 2, 3); alias myFoos = AliasSeq!(42, 43, 44); alias myBars = AliasSeq!(100, 200, 300); // A test with those 4 sets of template arguments alias result = staticMapN!(4, Instantiate, myTypes, mySizes, myFoos, myBars); pragma(msg, result); void main() { } I could not figure out eliminating the hard-coded 4. Can we introspect the parameter list of a template like 'fun' in the example? If we could, then we could get 4 that way. Ali
Re: Comparison of multidimensional associative arrays
On 2/8/23 11:04, Alexander Zhirov wrote: > That is, the result is arrays of table B that are missing OR not equal > to arrays in table A. This should do it: alias MyType = string[string][int]; // 'a' is subtracted from 'b' MyType difference(MyType b, MyType a) { MyType result; foreach (kv; b.byKeyValue) { auto existing = kv.key in a; if (!existing || (*existing != kv.value)) { result[kv.key] = kv.value; } } return result; } void main() { auto a = [ 4:["id":"4", "deleted":"f", "name":"6.2"], 3:["id":"3", "deleted":"f", "name":"5.6_hwlister"], 2:["id":"2", "deleted":"t", "name":"6.2"], 1:["id":"1", "deleted":"f", "name":"5.6"] ]; auto b = [ 6:["id":"6", "deleted":"f", "name":"6.2_test"], 5:["id":"5", "deleted":"f", "name":"5.6_test"], 4:["id":"4", "deleted":"f", "name":"6.2_hwlister"], 3:["id":"3", "deleted":"f", "name":"5.6_hwlister"], 2:["id":"2", "deleted":"f", "name":"6.2"], 1:["id":"1", "deleted":"f", "name":"5.6"] ]; auto expected = [ 6:["id":"6", "deleted":"f", "name":"6.2_test"], 5:["id":"5", "deleted":"f", "name":"5.6_test"], 4:["id":"4", "deleted":"f", "name":"6.2_hwlister"], 2:["id":"2", "deleted":"f", "name":"6.2"] ]; auto diff = difference(b, a); import std.format; assert(diff == expected, format!"UNEXPECTED: %s"(diff)); } Ali
Re: Comparison of multidimensional associative arrays
On 2/8/23 09:55, Alexander Zhirov wrote: > the differences Is it considered a difference if a key exists but the value is different? Or is that an error case if you encounter that? > return them when comparing: The representation seems difficult as well. When given this: > 6:["id":"6", "deleted":"f", "name":"6.2_test"], and that: > 6:["id":"6", "deleted":"f" ], Should the difference be 6:["name":"6.2_test"] ? And how to represent "missing from inner AA"? Just because this sounds complicated, I hope the data structure can be designed differently to be more friendly to this operation. (?) Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/6/23 23:33, ProtectAndHide wrote: > On Monday, 6 February 2023 at 21:46:29 UTC, Ali Çehreli wrote: >> And as 'static class' and 'static struct' are already usable in D, a >> newcomer would definitely be confused with your "terrible" conclusion. > You being a little agressive don't you think? I see how wrong that came out. Apologies! What I meant was "your conclusion [about something here being] terrible". > My observation is very reasonable, and correct, Agreed. > The compiler will allow you to do all these things Agreed. > I can see no reason why anyone would want to do these things, in this > context. Agreed. > Nor can I see any reason, whatsoever, why the compiler would allow you > to do these things, in this context. My understanding is that these are side-effects of trying to have orthogonal features. Some combinations don't make sense. Having said that, since D does not use 'static class' for namespacing, should it go out of its way to implement logic to ban that combination at module scope? Perhaps. People have been discovering meaningless combinations of attributes in D all the time. (I forgot why that is so.) If D disallowed 'static' at module scope, we wouldn't be having this discussion anyway. If that happened, then 'class' would be accepted for being used for creating objects. Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/6/23 23:45, ProtectAndHide wrote: > Well I don't agree that D should boast about things that's its > implemented in an unprincipled way. Here, "unprincipled"[1] is just a descriptive word meaning that D does not insist on certain software engineering methodologies e.g. unlike Java where "everything is a class" or unlike some functional programming languages where "everything must be immutable".[2] > an unprincipled > implementation of something that just allows you do make mistakes, then > it should be looked at further, so see if it can be improved. Agreed. But the lack of 'static class' in D or its approximations are not in that category. I can imagine someone coming up ingeniously with a harmful way of using 'static class' but unless that is a real problem that affects D users then there is no issue. Ali [1] I remember reading or hearing "unprincipled" from Andrei Alexandrescu long time ago. [2] Actually, const and immutable being transitive can be seen as counter examples of D having a strong point on something. I think this "turtles all the way down" is not agreed by many users.
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/6/23 12:56, ProtectAndHide wrote: > I'm not going to 'go write a > DIP'. Nobody will write a DIP about it because very few people ever mentioned this issue over the years. And as 'static class' and 'static struct' are already usable in D, a newcomer would definitely be confused with your "terrible" conclusion. Ali
Re: staticMap but with two arguments
On 2/5/23 17:20, John Chapman wrote: > staticMap's "fun" can only be > instantiated with a single argument, while I need it to work with two. I adapted staticMap's implementation to two sets of arguments: import std.meta : AliasSeq; // The first half of 'args' is the "first arguments" and // the second half is the "second arguments". // // (This can be generalized to N sets of arguments.) template staticMap2(alias fun, args...) { alias firsts = args[0 .. $ / 2]; alias seconds = args[$ / 2 .. $]; static assert(firsts.length == seconds.length, "Mismatched number of first and second arguments"); alias staticMap2 = AliasSeq!(); static foreach (i; 0 .. firsts.length) { staticMap2 = AliasSeq!(staticMap2, fun!(firsts[i], seconds[i])); } } // An example struct with two template parameters struct S(T, size_t length) { } // An example template that creates instantiations of the S template // (This can be generalized to instantiation of any template.) template Instantiate(T, size_t length) { alias Instantiate = S!(T, length); } // An example use alias myTypes = AliasSeq!(int, double, long); alias mySizes = AliasSeq!(1, 2, 3); alias result = staticMap2!(Instantiate, myTypes, mySizes); pragma(msg, result); void main() { } Ali
Re: ImportC "no include path set"
On 2/5/23 22:55, Elfstone wrote: > So how am I supposed to set the include path? I am not familiar with D in Windows but my first guess would be the -I compiler switch: dmd -I=/my/c/headers ... Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/5/23 18:15, ProtectAndHide wrote: > I do not agree, that a compiler that allows a programmer to misuse a > type Types normally have objects. If a programmer found a way to use objects of a memberless type why stop them? > should be seen as 'a feature'. I am not saying I already see those uses as features. I am questioning why the compiler should ban certain features. Rather, why would a programmer decide that another programmer should not have objects of a certain type? What is the actual insurmountable problem here? C#'s having 'static class' cannot be an answer because I can't imagine somebody even in C# wanted to have such a thing. For all I know, they wanted something else (namespacing in this case) and implemented it as 'static class'. On the other hand, it is possible that C# brings different semantics that I don't know yet. What is that semantics? How does D already solve that? > If that's the kind of 'power' D programmers want, The trait here is orthogonality: Let's say A, B, C, etc. are features of a language. Some combination of those features work together for various reasons. On the other hand, some combinations may not work well and people don't or can't use them for various reasons: - The language may ban them because there may be dangerous ambiguities with that combination - There may be technical impossibilities for that combination - That combination can have no agreeable semantics (your earlier examples are in this category) - People would never think about that combination (to me, at least some of your examples are in this category) - People may decide not to use that combination in coding guidelines - etc. So, what I am understanding is that thebluepandabear and you are asking the compiler to ban certain combinations. For example, using a struct for namespacing (A) and being able to create objects (B) used together should not be allowed. What other combinations can we come up with for such a list? As you said, certain uses of the 'static' keyword at module scope has no effect in D ('statis this' and 'shared static this' should be considered multi-word keywords and I think 'static const' has a meaning). Should the D spec enumerate all ineffective uses of 'static' (and others) and ban them? I don't agree. In contrast, D delivers some features in an unprincipled way and the programmers use combinations of those features the way the see fit. I really don't care if D had 'static class' to be used only as a namespace but I don't see how this issue is terrible. If the programmers ever need to use a struct (or a class) for namespacing then they wouldn't need objects of such types either. So, they wouldn't do that. Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/5/23 17:50, thebluepandabear wrote: > I don't see why you'd want I am not saying it would be wanted or needed. > to expose a static class/namespace as a > variable, or any of such similar things. That would give no benefits to > the programmer? Perhaps. As I responded to ProtectAndHide, if there is a benefit then it is useful by definition; if there is no benefit then it wouldn't be used anyway. Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/5/23 14:40, ProtectAndHide wrote: > On Sunday, 5 February 2023 at 10:51:51 UTC, thebluepandabear wrote: >> >> It's not a terrible workaround to be honest. >> > > The 'terrible' part is this: > > - the compiler will allow you to declare a variable of type Algo > - the compiler will allow you to declare an array with elements of type > Algo > - the compiler will allow you to use Algo as a type argument > - the compiler will allow you to use Algo as a parameter > - the compiler will allow you to use Algo as a return type I understand disabling the programmer to do certain things are beneficial e.g. to prevent bugs but those above can all be seen as features. What is so terrible about giving the programmer those powers? Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 2/5/23 02:57, thebluepandabear wrote: > When dealing with contexts, or for when you want a clear context in your > codebase, namespaces can be a life saver Can you give an example of a D problem that namespaces could solve? I have been with D for 14 years and haven't missed namespaces from C++ ever. The reason I ask is, mentioning lack of features of other programming languages is not the right way to go. We have to understand what problem they were trying to solve with that feature and then see how D already tackels it. In this case, it is namespacing and D solves it with the following feature and perhaps others that I can't think of: - modules - structs - classes - templates I don't consider myself a maintainer of D but I don't agree that yet another feature for namespacing is needed. I feel that it would bring complications. I don't think it is practical to bring all features of all languages into D or any other language. > we've seen it used in the D > library, so there's no excuse for why this shouldn't be added, in my > opinion. If I'm not mistaken you've counted five such instances. Were they really necessary? Could they be coded in a different way? What is the cost of missing namespaces? I think you are the first person raising this issue. You must have a strong case for this feature; so, I recommend you write a DIP for it. It is likely that the mere act of doing that will expose hidden costs and usage problems. Ali
Re: Are there some helpers in Phobos equivalent to std::set_difference of ugly c++
On 2/3/23 09:11, Ali Çehreli wrote: 'fold' is Ha ha! :) Make that 'reduce' of course. Ali
Re: Are there some helpers in Phobos equivalent to std::set_difference of ugly c++
On 2/3/23 08:01, Richard (Rikki) Andrew Cattermole wrote: All good, I'm glad it'll work for you :) I used the word difference to search the phobos docs with. 'fold' is doing much better in that department because it mentions other names: "Implements the homonym function (also known as accumulate, compress, inject, or foldl) present in various programming languages of functional flavor." https://dlang.org/library/std/algorithm/iteration/reduce.html Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 1/29/23 22:09, RTM wrote: > On Saturday, 28 January 2023 at 23:19:35 UTC, ProtectAndHide wrote: > >> That is, you can do OOP without classes > > How so? OOP is about putting objects (data) and behavior (functions) together. > Every OOP definition includes classes OOP is possible in C, which does not have classes: void sing(Animal * animal); That top-level sing function will do something like this: animal->sing(animal); Every object has their own sing function pointer as a member. (Or one can go to a vtbl pointer approach with different pros and cons; I used all of this as an interview topic at some point.) Programming languages just make it easy. > (encapsulation + inheritance). Encapsulation is available even in C as well. Inheritance can be achieved manually. And I used C just because it does not provide any special OOP features. Ali
Re: How to get the body of a function/asm statement in hexadecimal
On 1/29/23 14:19, max haughton wrote: > it is not trivial to find where the *end* of a > function is I suspected as much and did run ... > objdump ... to fool myself into thinking that 0xc3 was . Well, arguments e.g. pointer values can have 0xc3 bytes in them. So, yes, I am fooled! :) Ali
Re: How to get the body of a function/asm statement in hexadecimal
On 1/29/23 13:45, Ruby the Roobster wrote: > Of course, function pointers cannot be dereferenced. Since you want to see the bytes, just cast it to ubyte*. The following function dumps its own bytes: import std; void main() { enum end = 0xc3; for (auto p = cast(ubyte*)&_Dmain; true; ++p) { writefln!" %02x"(*p); if (*p == end) { break; } } } (It can be written more elegantly as a range expression.) > Furthermore, I would like to be able to do the same for an `asm` statement. I don't know how to get the address of asm blocks. Ali
Re: std.logger issue
On 1/26/23 12:08, Krzysztof Jajeśnica wrote: > On Thursday, 26 January 2023 at 17:17:28 UTC, o3o wrote: >> how can I enable `trace` level? > > Set `sharedLog.logLevel` instead of `globalLogLevel`. Good catch. I had tried the following without success: stdThreadLocalLog.logLevel = LogLevel.all; > // Note: the cast is needed because sharedLog is shared > (cast()sharedLog).logLevel = LogLevel.all; I did not think casting that way would be the right thing to do. Although I've never used std.logger, and without remembering who implemented it (sincere aplogies), given how simple the use cases of logging are, I found its implementation very complicated. For example, the following function is one I stumbled upon while debugging the OP's issue: bool isLoggingEnabled()(LogLevel ll, LogLevel loggerLL, LogLevel globalLL, lazy bool condition = true) @safe { return ll >= globalLL && ll >= loggerLL && ll != LogLevel.off && globalLL != LogLevel.off && loggerLL != LogLevel.off && condition; } I don't think it is possible to entagle usage issues with functions with that semantic complexity. Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 1/22/23 16:21, thebluepandabear wrote: > Again, stuffing it into a module is not the same thing as a namespace. That is correct but it is also one answer of D's to namespaces. There are others. For example, structs and classes provide namespacing as well. > The user can just bypass this by writing `drawLine`, there's nothing in > the language currently that would 'force' the user to write in a > namespace-like/static-class-like fashion, and that's the biggest problem. I agree with Adam here. The language should provide solutions and the programmer should pick appropriate ones. Later you added that you were talking about library design. There is no problem in the library providing an awesome and very usable API but the programmers still picking some other method that works better for them.[1] I would like to add to your C++ examples: Keyboard::Key.A// Fine Key.A // Fine foo// Fine That last line can exactly be the same as the previous two in C++. OOP is always a solution where it makes sense. I've been very happy with writing free-standing functions and dumb data types that the functions operate on... until... some invariant matters. Then I make the function a member, etc. Perhaps because I don't buy into the "everything is a class" anymore, I am very happy with D's approach. Mostly structs and functions for me. But I use classes as well when they make sense. Having said all that, I realize that your asking specifically for static classes made me think of a solution around classes. However, doesn't D has the equivalent in structs? Isn't the following what you are looking for? struct Algo { static void drawLine(Canvas c, Pos from, Pos to) { .. }; } Now the user is forced to use it like this: Algo.drawLine(new Canvas(), new Pos(5, 3), new Pos(7, 9)); or this: Algo().drawLine(/* ... */); but that can be @disabled. Ali [1] It is interesting that limiting the programmer in some way seems to help with language marketing. And D is deficient in that marketing move because it does the opposite: Gives the programmer choices. I tried to show this point on this slide: https://youtu.be/0JL9uT_XGZE?t=701 The point "not taking anything away from the programmer" can be seen as a marketing issue.
Re: Function which returns a sorted array without duplicates
On 1/21/23 23:33, evilrat wrote: > And IIRC you probably don't need `dup` Unfortunately, no. Skipping .dup is only possible if we are allowed to sort the original array. > as sort produces a lazy range. sort() returns a SortedRange but it can't be lazy. Even if it were, the first call to .front would have to sort anyway. However... There is an optimization possible for such requirements if not all elements but just a number of them are needed. For example, if only the first 10 elements are needed, then a binary heap may be faster: https://dlang.org/phobos/std_container_binaryheap.html The usage would be similar to the following for "the first 10 unique elements": heapify(arr).uniq.take(10) (Not tested.) Ali
Re: Non-ugly ways to implement a 'static' class or namespace?
On 1/20/23 07:01, torhu wrote: > But why not have drawLine just be a free function? Exactly. If I'm not mistaken, and please teach me if I am wrong, they are practically free functions in Java as well. That Java class is working as a namespace. So, the function above is the same as the following free-standing function in D, C++, C, and many other languages: void Algo_drawLine(Canvas c, Pos from, Pos to) { .. }; Ali
Re: What is the 'Result' type even for?
On 1/19/23 19:11, Ruby The Roobster wrote: > typeof(c).stringof.writeln; > The program prints: > > ["a", "b", "c", "d", "e"] > Result > > What is the purpose of this 'Result' type? Just to make sure, 'Result' is what the programmer of a Phobos algorithm chose to name a struct type. It could be anything. I will try to demonstrate it by naming my struct 'MyResult' below. The following range algorithm alternates between the two values it is called with. The pragma(msg) inside 'main' prints MyResult. auto alternate(T)(T a, T b) { // This function will return an object // of the following nested struct. // (Note: This is for demonsration // purposes only. Yes, this can be // be more optimal.) struct MyResult { bool useB = false; enum empty = false; // Infinite T front() { return useB ? b : a; } void popFront() { // Flip the selector useB = !useB; } } // Here, an object of the struct is // returned. It has single member (useB) // that it uses as a selector. // The values 'a' and 'b' are the actual // function arguments. return MyResult(); } import std; void main() { auto myRange = alternate(42, 7); // This prints 'MyResult' at compile time pragma(msg, typeof(myRange)); const expected = [ 42, 7, 42, 7, 42 ]; assert(myRange.take(5).equal(expected)); } > even when the type > has the same inherent function: Different instantiations of templates are distinct types. For example, if I called 'alternate' with two 'long' values, both alternate!int (as instantiated by the code above) and alternate!long would have different MyResult struct types. Although they would have the same functionality, they would be compiled potentially with very different CPU instructions and would not be assignable. Ali
Re: Problem with ImportC example?
On 1/18/23 08:04, DLearner wrote: > Unfortunately, neither works: > ``` > C:\Users\SoftDev>cl.exe > 'cl.exe' is not recognized as an internal or external command, > operable program or batch file. That supports the theory that you don't have a C compiler installed that dmd can use for preprocessing C files. Ali
Re: Problem with ImportC example?
On 1/17/23 12:02, DLearner wrote: C:\Users\SoftDev\Documents\BDM\D\ImportC>dmd ex01.c failed launching cl.exe /P /Zc:preprocessor [...] I don't use Windows for development but that error message makes me think cl.exe is not found to be executed. dmd relies on system compiler programs for its ImportC feature. cl.exe seems to be the compiler. I think it is the compiler. Can you run that program from the command line? Internet makes me think Visual Studio does not install it by default. (?) You may have to select C++ (or C?) when installing. (?) > FWIW, now tried a few standard D programs, work fine. > Suggesting VS is not the problem? Standard D programs don't need a C compiler; dmd is the D compiler. It needs a C compiler (to preprocess C sources) for ImportC. Ali
Re: Mixin helper help
On 1/13/23 18:51, bauss wrote: That's a good one! It looks like you liked it four years ago as well. :) I found where I remembered it from: https://forum.dlang.org/post/pvdoq2$1e7t$3...@digitalmars.com Ali
Re: Mixin helper help
On 1/13/23 00:48, bauss wrote: > 1. Change your mixin template to something like this: There was a technique as a workaround for this template mixin limitation but I can't find it right now. > 2. Change the place where you instantiate to this: I think the workaround I am trying to remember would not require any change for the users. Ok, it was something like this: mixin template myStatement() { auto doIt() { import std.stdio : writeln; writeln("hi"); return 0; } auto ignoreThis = doIt(); } void main() { mixin myStatement!(); mixin myStatement!(); } Ali
Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)
On 1/13/23 07:22, Gavin Ray wrote: > Maybe it would be better to wrap the slice in a new class with an > invariant? Possibly but please check before using because I think 'invariant' requires presence of member functions: https://dlang.org/spec/struct.html#Invariant > Because what I want to do is: > > 1. Ensure that the length of the underlying referenced/pointed-to data > is `PAGE_SIZE` My first thought was why not use a slice anyway? Worth noting that static arrays are value types. Also, they all have different types from each other and have the potential to cause template bloat. > class BufferPool Off-topic, most D programmers use struct unless they need class. > Frame[BUF_POOL_NUM_PAGES] frames; Makes sense to me. Ali
Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)
On 1/13/23 07:07, Gavin Ray wrote: > This is "valid" D I hope? Yes because static arrays are just elements side-by-side in memory. You can cast any piece of memory to a static array provided the length and alignment are correct. However, such a cast is not allowed in @safe code. Ali
Re: Creating a pointer/slice to a specific-size buffer? (Handing out a page/frame from a memory manager)
On 1/13/23 06:49, Gavin Ray wrote: > I am curious if you can return something like `ubyte[PAGE_SIZE]*` or > `ref ubyte[PAGE_SIZE]`? A simple cast seems to work: enum PAGE_SIZE = 4096; enum BUF_POOL_NUM_PAGES = 1024; alias frame_idx_t = size_t; ubyte[10_000] data; ubyte[PAGE_SIZE]* get_page(frame_idx_t frame_idx) { auto ptr = data.ptr + frame_idx * PAGE_SIZE; return cast(ubyte[PAGE_SIZE]*)ptr; } void main() { } Ali
Re: enum functions
TLDR Eponymous templates that define a function pointer does not transfer the function call parameter to the enclosing template for type deduction. (Note: The term "deduction" is used with template parameters, not "inference".) Also note that I am replacing 'enum' with 'auto' below to show this is not related to 'enum' vs 'auto'. template foo (T) { auto foo = (T i) => i >> 1; } void main() { foo(42); // <-- Compilation ERROR } Error: none of the overloads of template `deneme.foo` are callable using argument types `!()(int)` Candidate is: `foo(T)` I am not sure whether this limitation is a bug. TLDR On 1/11/23 10:01, Salih Dincer wrote: > void main() > { > enum foo : char { a = 'H', b = 'i' } That defines two values: foo.a is 'H' and foo.b is 'i'. > enum bar() { return new foo; } That is a function that returns a dynamically allocated foo value. Since 'new' makes pointers for value types like int and enum, I think the return type of 'bar' is foo*. And that pointer is pointing at a foo.init, which happens to be the first value defined: 'H'. > > import std.stdio; > foreach(char f; [bar.a, bar.b]) 'bar' is a function call that returned a pointer. Hm. Finally I see what you are talking about. Normally, one might have written (*bar) to get the value. Let's try by using the following array: [(*bar), (*bar)] Ok, it's what I expect: HH Now the interesting part is what does (*bar).a and (*bar).b mean? Let's try: [(*bar).a, (*bar).b] Ok, it gives Hi The interesting thing is, foo.a does not print 'H' but 'a': writeln(foo.a); writeln(foo.b); a b Ah! Finally I see your explicit 'char' in the foreach loop. That is what makes your code print 'H' and 'i'. :) > f.write; > > writeln; // Hi > } I've just learned something: You can reach different enum values directly from an value itself: import std; void main() { // A type: enum foo : char { a = 'H', b = 'i' } // A variable: enum x = foo.a; // Really? writeln(x.b); } Ok, it kind of makes sense but I would have written the following e.g. in template code. (?) writeln(typeof(x).b); > I think this use of enums should be prohibited. So, can I get an answer > about not being able to make a type inference? So I'm very curious about > the second part of the my post. Before looking at your example, here is what I tested. The code proves that type inference is the same for 'auto' and 'enum' functions: auto foo(T)(T t) { return t; } enum bar(T)(T t) { return t; } struct S {} import std.meta; void main() { alias functions = AliasSeq!(foo, bar); alias types = AliasSeq!(int, double, S, string, const(float)); static foreach (type; types) { pragma(msg, "Testing ", type); static foreach (func; functions) { static assert (is (typeof(func(type.init)) == type)); } } } It uses two function templates and a few types and as expected, the return types of the functions are the same. Ok, back to your code: > template foo (T) { > enum foo = (T i) => i >> 1; > } That local 'foo' is a literal value of an anonymous function. (The local 'foo' is not a template.) Reminding myself: Literals are rvalues and they are not variables. For example, they don't have addresses. > template bar (T) { > auto bar (T i) => i >> 1; > } That's different: There was an equals sign after 'foo' but not here. So your example is different from e.g. the following two definitions: auto x() {} enum y() {} If you are curious about this case, as Adam said, there is no difference between 'auto' and 'enum'. But again, your code has that extra '=' character for 'foo' and that makes a difference. Getting back to 'bar', so that local 'bar' is a function definition. Now, calling bar from the outside as bar(42) is the same as writing bar!int.bar(42). (This is the eponymous template convenience.) > import std; > void main() > { > assert(oneHalf(42) == 21); > 42.foo!int.writeln; // no inference: "21" Your "no inference" comment was confusing me. Now I see that you meant that you can't write the following: 42.foo.writeln; // <-- Compilation ERROR Although you can write the following: > 42.bar.writeln; // "21" > } Ok, let's look at the problem with the understanding of 'foo' being a literal. Yes, I can demonstrate the issue that mix it with the concept of type inference: import std; void main() { enum foo = { // Note '=' writeln("foo"); }; auto bar() { writeln("bar"); } foo; // <-- Compilation ERROR bar; } foo line has a compilation error: Error: `__lambda1` has no effect Because it's a function pointer, one needs to call it with parenthesis: foo(); bar; Now it works. The reason why 'bar' does not need the parenthesis is because functions have that famous
Re: Coding Challenges - Dlang or Generic
On 1/9/23 16:17, Paul wrote: > coding challenges Perhaps the following two? https://rosettacode.org/ https://adventofcode.com/ Ali
Re: Bug or feature? iota has different semantics for integer and float arguments
On 1/6/23 17:50, Arredondo wrote: > Would anyone volunteer to file a bug report? Me! Me! :) https://issues.dlang.org/show_bug.cgi?id=23604 Ali
Re: Bug or feature? iota has different semantics for integer and float arguments
On 1/6/23 15:23, Arredondo wrote: > then you get an exception (incorrect startup parameters). Although that difference is a bug, iota does have a special floating point implementation to prevent the accumulation of floating point errors. I mention it as item 4 here: https://www.youtube.com/watch?v=gwUcngTmKhg&t=634s Briefly, iota's regular popFront() is a trivial front += step but it is ++n for floating types so that front can be begin + (n * step) for them. The iota discussion starts at an earlier point in the video here: https://www.youtube.com/watch?v=gwUcngTmKhg&t=558s Ali
Re: Address of a class object
On 1/4/23 20:04, Paul wrote: >> (Again, there is no problem here; we are just learning.) >> Ali > > Do I have this much right? > ..with this output? Looks good to me. While we're here, you can force the class objects to be on the stack as well: scope MyClassVar1 = new MyClass(); I replaced 'auto' with 'scope'. Ali