Re: Template pattern delegate?
On 10/25/20 4:30 AM, frame wrote: Is there a possibility to write templated code / custom trait pattern with usage like a delegate? I have a try-catch block with different types and don't want to repeat myself in every method again. It's always the same, just what's tried changes, eg.: pseudo code: template myStuff(mixin code) { try { code(); } catch (X e) { ... } catch (Y e) { ... } ... } static myStuff!({ writeln("..."); }); That's one of my DConf Onlide slides but for a limited use case! :) int tried(Func, string functionName = __FUNCTION__, string file = __FILE__, size_t line = __LINE__)(Func func) { static if (!is (ReturnType!Func == int)) { pragma(msg, format!"\n%s(%s): Error: %s must return int error code"(file, line, functionName)); static assert(false); } void printError(T)(T err) { stderr.writefln!"\n%s(%s): Failed to execute %s: %s"(file, line, functionName, err); } try { return func(); } catch (Exception exc) { printError(exc.msg); return 1; } catch (Error err) { printError(err); import core.stdc.stdlib : abort; abort(); } assert(false); } Then, all extern(C) functions would be written the same way: extern(C) int foo() { return tried({ // ... return 0; }); } Ali
Re: toStringz lifetime
On 10/25/20 3:19 AM, rikki cattermole wrote: On 25/10/2020 11:03 PM, Ali Çehreli wrote: Does the GC see that local variable 'name' that is on the C side? What I don't know is whether the GC is aware only of the stack frames of D functions or the entire thread, which would include the C caller's 'name'. The thread stack frame that is registered with the D GC will know about the D side and may know about the C side. It depends on what the C side is doing. If the C side went ahead and made a new stack frame via a fiber... it won't know about it. But even if it did, the D stack frame is still alive and pinning that bit of memory. Ultimately, if the C side puts that pointer some place like a global or send it to another thread, there are no guarantees that things will play out well. Thanks. That's reassuring. :) So, as long as the D function documents that the C side should make a copy if they want to extend the string's lifetime it's their responsibility. And from your description I understand that they have time to make that copy. Ali
toStringz lifetime
toStringz documentation is clear on why, when, and how to extend the lifetime of a D string: https://dlang.org/phobos/std_string.html#.toStringz Assume foo is a D library function that passes a "string" result to e.g. C: extern(C) void foo(ref const(char) * name) { name = format!"file%s.txt"(42).toStringz; // Allocates from GC memory } This may be fine for "immediate use" on the C side because at first glance no garbage collection can take place between our returning the result and their using it: // C caller: const char * name = NULL; foo(); // Calls us printf("%s", name); // Uses 'name' immediately Is it really safe? Imagine a multi-threaded environment where another D function is executed that triggers a GC collection right before the printf. Does the GC see that local variable 'name' that is on the C side? What I don't know is whether the GC is aware only of the stack frames of D functions or the entire thread, which would include the C caller's 'name'. Ali
Re: Two ways of receiving arrays on the C ABI
On 10/19/20 6:28 PM, Nicholas Wilson wrote:> On Tuesday, 20 October 2020 at 00:16:48 UTC, Ali Çehreli wrote: >> On the D side, both of the following extern(C) functions take the same >> arguments. > > https://github.com/dlang/dmd/pull/8120 > > there are issues with structs. Not sure about length/ptr. Thank you, Nic. I see that doing the following is undefined behavior: extern(C) void dFunc(int[] arr) {// <-- Takes slice assert(arr.equal(3.iota)); } // A C function void dFunc(size_t length, int * ptr); // <-- Passes length+pointer int arr[] = { 0, 1, 2 }; dFunc(3, arr); C does not define an ABI. So, length+pointer can be passed in any way from there. The good thing is that D is aware of the "C Application Binary Interface of the target system"[1] but that means D would support taking length+pointer as well. Slice arguments are still strictly in length+pointer order for D. So, it works on my Linux system by chance. Ali [1] https://dlang.org/spec/abi.html
Two ways of receiving arrays on the C ABI
On the D side, both of the following extern(C) functions take the same arguments. 1) func1 takes .length and .ptr implicitly as parts of a D array: extern(C) void func1(int[] arr) { assert(arr.equal(3.iota)); } 2) func2 takes .length and .ptr separately and then makes a slice explicitly: extern(C) void func2(size_t length, int * ptr) { auto arr = ptr[0..length]; assert(arr.equal(3.iota)); } C side declares and calls both of them the same way: void func1(size_t length, int * ptr); void func2(size_t length, int * ptr); int arr[] = { 0, 1, 2 }; func1(3, arr); func2(3, arr); Everything works at least on Linux. Is this kosher, or am I using some internal knowledge? Here is the ABI spec: https://dlang.org/spec/abi.html One of the DConf Online 2020 slides thanks you! ;) Ali
Re: Forward referencing functions in D
On 10/17/20 8:28 AM, NonNull wrote: On Friday, 16 October 2020 at 21:28:18 UTC, Steven Schveighoffer wrote: Inner functions have benefits: 1. They are only accessible inside the function. Which means you only have to worry about correctness while INSIDE that function. 2. inner functions have access to the outer function's stack frame. Often, I use inner functions to factor out a common piece of code that I don't want to have to write multiple times in the same function. -Steve How can you write two inner functions that call each other? (Recursively) I thought of the following method just now. Yes, there are lambdas but who cares? :) (Besides, 'a' can be defined as a proper function below.) import std.range; void foo(string s) { // b is not initialized yet void delegate() b; // a is initialized auto a = { while (!s.empty) { s.popFront(); b(); } }; // Set b to a lambda b = { while (!s.empty) { s.popBack(); a(); } }; a(); } void main() { foo("hello"); } Ali
Re: why do i need an extern(C): here?
On 10/16/20 4:12 PM, WhatMeWorry wrote: > Isn't dlopen() for Linux More like dlopen() is for Posix, which means it should be available on Windows as well. However, as I've discovered, a D shared library cannot be loaded with dlopen() because the main program and the shared library would do their own garbage collection (presumably with separate GC states) without being aware of each other and this won't work. Runtime.loadLibrary() knows to do the right thing and both sides are aware of each other. > and LoadLibrary() for Windows? Yes, but I am talking about core.runtime.Runtime.loadLibrary, which should call appropriate functions depending on the operating system. > Or are you > running Windows I run Windows with mild disgust :p only for work-related applications. Otherwise, it's all Linux. Ali
Re: How can I convert Hexadecimal to RGB Color and vice-versa?
On 10/16/20 1:10 PM, Marcone wrote: How can I convert Hexadecimal to RGB Color and vice-versa? On 10/16/20 1:10 PM, Marcone wrote: > How can I convert Hexadecimal to RGB Color and vice-versa? Do you mean from a string like "#123456" to the values of red, green, and blue? I am having more fun with D than usual. So, I wrote the following without understanding your requirements. :) I am sure this already exists in various libraries. import std.exception; import std.range; import std.format; import std.stdio; import std.traits; struct RGB { ubyte red; ubyte green; ubyte blue; this(const(char)[] s) { enforce(s.length < 8, format!`Invalid RGB string: "%s"`(s)); if (s.front == '#') { s.popFront(); } uint value; s.formattedRead!"%x"(value); this(value); } this(T)(T value) if (isIntegral!T) { enforce(value >= 0 && value < 0x100_, format!"Invalid RGB value: %s (0x%,*?x)"(value, 2, '_', value)); ubyte popLowByte() { ubyte b = value & 0xff; value >>= 8; return b; } this.blue = popLowByte(); this.green = popLowByte(); this.red = popLowByte(); assert(value == 0); } string asHex() { return format!"%02x%02x%02x"(red, green, blue); } } void main() { auto a = RGB("#a0a0a0"); writeln(a); auto b = RGB(0x10ff20); writeln(b); writeln(b.asHex); } Ali
Re: Forward referencing functions in D
On 10/16/20 1:47 PM, wilcro wrote: > would > there be any reason to avoid placing the majority of code for a program > outside of the main function? Keeping scopes of symbols as small as possible is a general guideline in D and elsewhere but I wouldn't crowd my main() function with details of program logic either. (Aside: There is no global name scope in D; everything belongs to a module.) One thing I love about D is that there are no strong principles like that. I code in a way that is comfortable and change things later on as a needs arise. :) Ali
Re: Packing of Struct Fields
On 10/16/20 1:32 PM, Per Nordlöw wrote: Why is `T.sizeof` 12 instead of 8 when `U.sizeof` is 8 in the following example? struct S { int i; bool b; } struct T { S s; char c; } struct U { int i; bool b; char c; } ? I have a function that dumps member layout of structs, which someone may find useful: http://ddili.org/ders/d.en/memory.html#ix_memory..offsetof It prints the following for these types: === Memory layout of 'S' (.sizeof: 8, .alignof: 4) === 0: int i 4: bool b 5: ... 3-byte PADDING === Memory layout of 'T' (.sizeof: 12, .alignof: 4) === 0: S s 8: char c 9: ... 3-byte PADDING === Memory layout of 'U' (.sizeof: 8, .alignof: 4) === 0: int i 4: bool b 5: char c 6: ... 2-byte PADDING Copied here: struct S { int i; bool b; } struct T { S s; char c; } struct U { int i; bool b; char c; } void printObjectLayout(T)() if (is (T == struct) || is (T == union)) { import std.stdio; import std.string; writefln("=== Memory layout of '%s'" ~ " (.sizeof: %s, .alignof: %s) ===", T.stringof, T.sizeof, T.alignof); /* Prints a single line of layout information. */ void printLine(size_t offset, string info) { writefln("%4s: %s", offset, info); } /* Prints padding information if padding is actually * observed. */ void maybePrintPaddingInfo(size_t expectedOffset, size_t actualOffset) { if (expectedOffset < actualOffset) { /* There is some padding because the actual offset * is beyond the expected one. */ const paddingSize = actualOffset - expectedOffset; printLine(expectedOffset, format("... %s-byte PADDING", paddingSize)); } } /* This is the expected offset of the next member if there * were no padding bytes before that member. */ size_t noPaddingOffset = 0; /* Note: __traits(allMembers) is a 'string' collection of * names of the members of a type. */ foreach (memberName; __traits(allMembers, T)) { mixin (format("alias member = %s.%s;", T.stringof, memberName)); const offset = member.offsetof; maybePrintPaddingInfo(noPaddingOffset, offset); const typeName = typeof(member).stringof; printLine(offset, format("%s %s", typeName, memberName)); noPaddingOffset = offset + member.sizeof; } maybePrintPaddingInfo(noPaddingOffset, T.sizeof); } void main() { printObjectLayout!S(); printObjectLayout!T(); printObjectLayout!U(); } Ali
Re: Struct field destructor not called when exception is thrown in the main struct destructor
On 10/16/20 9:05 AM, Steven Schveighoffer wrote: > The destruction of members is outside the destructor's purview. It can't > turn the destruction off, so it should logically be considered part of > an enclosing function. Thank you. Makes sense. Ali
Re: why do i need an extern(C): here?
On 10/15/20 2:42 PM, Ali Çehreli wrote: > I've recently done the same by calling dlopen() and dlsym() > directly. Runtime.loadLibrary documentation says "If the library > contains a D runtime it will be integrated with the current runtime." > That would explain why my program seg-faults for my first tester with > the garbage collector signatures in the function call stack. Replacing dlopen() with Runtime.loadLibrary() did solve the segfault issue for me. Ali
Re: Struct field destructor not called when exception is thrown in the main struct destructor
On 10/16/20 6:12 AM, tchaloupka wrote: > struct Foo { > Bar bar; > bool err; > > ~this() { > // scope(failure) destroy(bar); // < this fixes the Bar > destructor call > enforce(!err, "Test err"); Well, that check means "cannot continue", which means the compiler stops executing the destruction code because it can't. (It would a serious bug if it continued execution in a state that the program knows to be invalid.) > } Conceptually, bar's destructor is called on that closing brace but we decided to abort mission earlier. Your calling destroy(bar) may or may not be wrong in case of 'err'. Only you know at that point. > Is this behavior expected? Yes. Ali
Re: why do i need an extern(C): here?
On 10/15/20 2:29 PM, WhatMeWorry wrote: > name wrangling? Name mangling. :) I don't know the answer but I can hijack your thread. > import core.runtime; > auto mydll = Runtime.loadLibrary("mydll.dll"); Interesting. I've recently done the same by calling dlopen() and dlsym() directly. Runtime.loadLibrary documentation says "If the library contains a D runtime it will be integrated with the current runtime." That would explain why my program seg-faults for my first tester with the garbage collector signatures in the function call stack. Right? Thanks! :) Ali
Re: malloc(s)[0..s] vs cast(T)malloc(s)
On 10/14/20 1:15 PM, Jack wrote: >> auto x = malloc(s)[0..s]; > https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation Note that 'x' is passed to emplace() at that link and emplace() requires a slice. That's why the a slice is made from the pointer returned by malloc(). Ali
Re: Passing pointer to extern(C++) templated function
On 10/13/20 4:11 PM, James Blachly wrote: On 10/13/20 5:23 AM, Jamie wrote: Building with: g++ -c a.cpp dmd main.d a.o Throws the error: /usr/bin/ld: main.o: in function `_Dmain': main.d:(.text._Dmain[_Dmain]+0x31): undefined reference to `void func3(int*, int*)' /usr/bin/ld: main.d:(.text._Dmain[_Dmain]+0x3e): undefined reference to `void func4(int const*, int const)' collect2: error: ld returned 1 exit status Error: linker exited with status 1 Is the template even instantiated? With just a template definition and an object file I am surprised you even have a symbol? Yes, they all have explicit template instantiations on the C++ side. I think the issue is with D's "turtles all the way down" style const. My workaround would be to define wrapper functions that may need to do casting on one or the other side. Ali
Re: List of exceptions?
On 10/12/20 2:11 AM, Dominikus Dittes Scherkl wrote: > - Throw exceptions only if you have a plan what to do with them if you > catch them. My thinking is different: Throw exceptions if you can't accomplish a task. My code is filled with enforce() and assert() checks, which do throw exceptions. > - If you have no plan, better throw error, just to get an idea where and > why the program crashed (and don't try to catch them) In most cases, catching Exception (not Error) to print exc.msg is fine and is the correct thing to do. (Errors are not caught, the stack trace is printed, and that's helpful.) Occasionally, exc.msg of an Exception doesn't give enough information. So, printing exc (not exc.msg) temporarily to look at the stack trace is helpful. Ali
Re: Renaming Flag!"" in API
It's amazing how things come together before each conference. Flag appears among my slides for an upcoming conference as well! :) But I don't think there is any solution to your problem. On 10/12/20 3:24 AM, FreeSlave wrote: > Later I realize that 'myflagname' is a bad name and I want to change it > to something else. But if I do so, I break the existing code using this > API as Flag with different name will be a different type This is essentially the same as one of the objections to named arguments. Ali
Re: Range format specifiers in other languages?
On 10/11/20 5:44 PM, Max Haughton wrote: > Possibly worth showing off (especially given that some people at first > don't even know the templated format string exists) This feature is already among my slides for an upcoming conference. ;) Ali
Range format specifiers in other languages?
I find D's %( and %) range format specifiers very useful: import std.stdio; import std.range; void main() { 5.iota.writefln!"%(%s, %)"; // Prints 0, 1, 2, 3, 4 } Are there similar features in other languages? Thank you, Ali
Re: List of exceptions?
On 10/10/20 12:51 PM, DMon wrote: > I will copy that down. > > The idea for specific exceptions came from the online docs and > Programing in D, 39.2 The try-catch statemet > > try > { // the code block that is being executed, where an // exception may be > thrown > } > catch (an_exception_type) > { // expressions to execute if an exception of this // type is caught > } > catch (another_exception_type) > { // expressions to execute if an exception of this // other type is > caught // ... more catch blocks as appropriate ... > } > finally > { // expressions to execute regardless of whether an // exception is thrown > } I don't have time right now to write longer but I see how that can be confusing and apologize for the confusion. :( In general, forget all of that and just catch Exception. :) That's all you need. And 'finally' is almost never used in D. Ali
Re: List of exceptions?
On 10/10/20 9:16 AM, DMon wrote: > catch (Exception e) // implicit (any exception) > catch (ConvException f) // explicit (conversion only) > > Or is that not correct? I think in class hierarchies, "more general" and "more specific" are better terms. :) The answer is, catch by the most general under the Exception hierarchy that you care about. It depends on the program. In most of my programs, catching Exception in main is sufficient because I just print the error message. However, sometimes the error message does not make sense at that level: void foo() { // The error thrown during this may not be meaningful to // the user of the program: // "Unexpected 'h' when converting from type string to type int" "hello".to!int; } So, you can augment that error with another one: import std.conv; import std.stdio; import std.format; class FooException : Exception { string msg; Exception actual; this (Exception e) { this.msg = format!"Failed to do foo: %s"(e.msg); super(this.msg); this.actual = e; // Store for more information later } } void foo() { try { "hello".to!int; } catch (Exception e) { // Convert to a more meanigful exception: throw new FooException(e); } } int main() { try { foo(); } catch (Exception e) { stderr.writefln!"ERROR: %s"(e.msg); return 1; } return 0; } One cool thing about storing the 'actual' exception is, you can later debug it by catching the specific FooException and printing 'actual' as is, which contains the stack trace: int main() { try { foo(); // Added for debugging: } catch (FooException e) { // Printing as is contains the stack trace: stderr.writeln(e.actual); return 1; } catch (Exception e) { stderr.writefln!"ERROR: %s"(e.msg); return 1; } return 0; } But really, it all depends on your program. The simplest thing may to not catch at all. The default behavior is to dump the stack trace and it works for some programs. Ali
Re: List of exceptions?
On 10/10/20 8:46 AM, DMon wrote: On Saturday, 10 October 2020 at 14:56:31 UTC, Ali Çehreli wrote: On 10/10/20 5:12 AM, DMon wrote: Is there a list of a list of the exceptions or what can be used with catch? Only Throwable and classes that are derived from it can be thrown and caught. Ali Thanks for the reply. I am looking to catch exceptions explicitly and get that it does not have to be. Is explicite cathing the best practice or is implicite how its done? I don't know implicit catching. I would like to learn from others. I think the common rules are: - Don't catch anything - Unless you can do something about it (e.g. ask the user something to retry, augment it, etc.) I almost always catch in main() (or a thread's main function) and only to print a clean error message: void main() { try { // ... } catch (Exception e) { stderr.writefln!"ERROR: %s"(e.msg); } } That's it for me. :) Ali
Re: List of exceptions?
On 10/10/20 5:12 AM, DMon wrote: Is there a list of a list of the exceptions or what can be used with catch? I'm thinking that I missed it and there is something easier than breaking old code, scouring the site, or hypnotic regression. Only Throwable and classes that are derived from it can be thrown and caught. It has two decendants: Throwable / \ Error Exception Throwable and Error are caught very rarely in special situations. For example, a thread may catch all types of exceptions to report the reason why it's about to die. So the only type that is and should be used in most programs is Exception: void main() { try { foo(); } catch (Exception e) { writefln!"Something bad happened: %s"(e.msg); // You can continue if it makes sense } } So, programs base their exceptions on Exception: class MyException : Exception { this(int i) { import std.format; super(format!"Bad int happened: %s"(i)); } } void foo() { throw new MyException(42); } void main() { foo(); } There are helpers in std.exception e.g. class MyException : Exception { import std.exception; mixin basicExceptionCtors; } void foo() { throw new MyException("a problem happened"); } void main() { foo(); } I have some basic information here: http://ddili.org/ders/d.en/exceptions.html Ali
Re: Efficient sort function allowing own test and swap function as parameter
On 10/6/20 3:18 PM, Alaindevos wrote: I have a large table consisting of two columns.One with words.Another with frequencies. I want to sort them efficiently according to the names or frequency. For this I need an efficient sort function where I can plugin my proper test of order, and proper swap. Currently I do it using an own written bubble sort that doesn't scale well. I had fun writing the following program. Note how makeIndex allows visiting elements in sorted order without actually sorting them. import std.random; import std.range; import std.algorithm; import std.conv; import std.stdio; struct S { string word; size_t frequency; } bool byWord(S a, S b) { return a.word < b.word; } bool byFrequency(S a, S b) { return a.frequency < b.frequency; } auto dump(R)(string title, R range) { writefln!"\n%s:\n%(%s\n%)"(title, range); } // A test function that makes an S S makeS() { string makeWord() { static letters = iota('a', 'z' + 1).map!(to!dchar).array; return letters.randomSample(4).to!string; // Four-letter words! :p } size_t makeFrequency() { return uniform(0, 100); } return S(makeWord(), makeFrequency()); } // A test function that makes some S'es S[] makeSs() { return 10.iota.map!(i => makeS()).array; } void main() { auto ss = makeSs(); dump("Unsorted", ss); auto byWordIndexes = new size_t[ss.length]; ss.makeIndex!byWord(byWordIndexes); dump("Still unsorted but visited by word order", byWordIndexes.map!(i => ss[i])); auto byFrequencyIndexes = new size_t[ss.length]; ss.makeIndex!byFrequency(byFrequencyIndexes); dump("Still unsorted but visited by frequency order", byFrequencyIndexes.map!(i => ss[i])); ss.sort!byWord(); dump("Actually sorted by words", ss); ss.sort!byFrequency(); dump("Actually sorted by frequencies", ss); } Sample output: Unsorted: S("bfmp", 78) S("imsx", 17) S("kmwy", 60) S("klpw", 92) S("hnrt", 24) S("aivz", 29) S("prst", 24) S("cdlm", 86) S("alvz", 13) S("mnxz", 52) Still unsorted but visited by word order: S("aivz", 29) S("alvz", 13) S("bfmp", 78) S("cdlm", 86) S("hnrt", 24) S("imsx", 17) S("klpw", 92) S("kmwy", 60) S("mnxz", 52) S("prst", 24) Still unsorted but visited by frequency order: S("alvz", 13) S("imsx", 17) S("hnrt", 24) S("prst", 24) S("aivz", 29) S("mnxz", 52) S("kmwy", 60) S("bfmp", 78) S("cdlm", 86) S("klpw", 92) Actually sorted by words: S("aivz", 29) S("alvz", 13) S("bfmp", 78) S("cdlm", 86) S("hnrt", 24) S("imsx", 17) S("klpw", 92) S("kmwy", 60) S("mnxz", 52) S("prst", 24) Actually sorted by frequencies: S("alvz", 13) S("imsx", 17) S("hnrt", 24) S("prst", 24) S("aivz", 29) S("mnxz", 52) S("kmwy", 60) S("bfmp", 78) S("cdlm", 86) S("klpw", 92) Ali
Re: It is possible to substract 5 from 3 unsigned integer
On 10/6/20 5:24 AM, Alaindevos wrote: Is that the expected behavior of the programmer? Opinions can differ. Feel free to elaborate. The following is even more "expected". ;) Subtract zero from -1 and you get size_t.max. void main() { int[] arr; int i = -1; auto u = (i - arr.length);// -1 - 0 assert(u == size_t.max); // the surprise static assert (is (typeof(u) == size_t)); // the reason } Ali
Re: Deprecation in traits
On 9/29/20 10:08 AM, Frak wrote: Hi folks, I've this: /Users/frak/dlang/ldc-1.23.0/bin/../import/std/traits.d(3711): Deprecation: function `std.typecons.Nullable!long.Nullable.get_` is deprecated - Implicit conversion with `alias Nullable.get this` will be removed after 2.096. Please use `.get` explicitly. I'm trying to find out WHERE this is generated to fix it, dependency included, without success. Suggestions? I've just ported my code to 2.094 and had to clean up that issue. Luckily, in my case they were all in user code. I had to access my Nullable objects with .get: if (n) { // n.foo();<-- from n.get.foo(); <-- to } So, look at all your Nullable objects maybe. Ali
Re: Memory management
On 9/29/20 3:57 AM, novice3 wrote:> Naive newbie question: > > Can we have (in theory) in D lang memory management like V lang? > > Quote: > https://github.com/vlang/v/blob/master/doc/docs.md#memory-management > > "V doesn't use garbage collection or reference counting. The compiler > cleans everything up during compilation. If your V program compiles, > it's guaranteed that it's going to be leak free." I am not a language expert but I can't imagine how the compiler knows whether an event will happen at runtime. Imagine a server program allocates memory for a client. Let's say, that memory will be deallocated when the client logs out or the server times that client out. The compiler cannot know either of that will ever happen, right? Ali
Re: How does alias exactly work
On 9/28/20 6:46 PM, Ruby The Roobster wrote: I thought alias could work like this with classes: That would work with template parameters: alias A = Foo!(3, "hello"); alias test = MyClass(3,"H",9.1); //Assume the constructor parameters for MyClass are (int,string,double). Can anybody fix this code? You have to write a function (or a lambda): class MyClass { this(int, string, double) { } } auto test1() { return new MyClass(3,"H",9.1); } auto test2 = () => new MyClass(4, "I", 10.1); void main() { test1(); test2(); } However, I assumed each invocation would create a new object. If not, something like this: MyClass test3; static this() { test3 = new MyClass(5, "J", 11.1); } test3 is a single instance for each thread. A single instance for the whole program would be a different exercise. :) Ali
Re: How to hide a function return type in order to wrap several functions into an associated array?
On 9/27/20 11:54 AM, tastyminerals wrote: > I have a collection of functions that all have the same input, a string. > The output however is different and depending on what the function does > it can be ulong, double or bool. The following approach overcomes the different return type issue by creating delegates that take string and return string: auto numberOfPunctChars(string text) { return 42; } auto ratioOfDigitsToChars(string text) { return 1.5; } auto hasUnbalancedParens(string text) { return true; } struct FeatureSet { alias TakesString = string delegate(string); TakesString[] features; void register(Func)(Func func) { // Here, we convert from a function returning any type // to a delegate returning string: features ~= (string s) { import std.conv : text; return func(s).text; }; } // Here, we apply all feature delegates and put the outputs // into the provided output range. void apply(O)(ref O outputRange, string s) { import std.format : formattedWrite; import std.algorithm : map; outputRange.formattedWrite!"%-(%s\n%|%)"(features.map!(f => f(s))); } } void main() { auto featureSet = FeatureSet(); featureSet.register(); featureSet.register(); featureSet.register(); // lockingTextWriter() just makes an output range from // an output stream. import std.stdio; auto output = stdout.lockingTextWriter; featureSet.apply(output, "hello world"); // As another example, you can use an Appender as well: import std.array : Appender; auto app = Appender!(char[])(); featureSet.apply(app, "goodbye moon"); writefln!"Appender's content:\n%s"(app.data); } Ali
Re: A scheduled control signal with fibers?
On 9/27/20 6:33 AM, Ferhat Kurtulmuş wrote: > On Sunday, 27 September 2020 at 12:05:13 UTC, Ferhat Kurtulmuş wrote: >> On Sunday, 27 September 2020 at 10:40:25 UTC, Ali Çehreli wrote: >>> On 9/27/20 3:06 AM, Ferhat Kurtulmuş wrote: > > Oh, It will work fine if I imitate my time-consuming image processing > like this. > I think it is Ok now. > > import std.stdio; > import std.concurrency; > import core.thread; > > void main() { > foreach (v; 0..10){ > auto childTid = spawn(, thisTid); How many flame threads do you need? I thought one image processor and one flame thrower, no? Even if you have a dozen of each, main can start only the image processing threads and then each image processor can start its own flame thrower. Then, each pair will have an owner and a worker. You don't need to send thisTid because every thread already has an ownerTid defined: auto childTid = spawn(); > Thread.sleep(10.msecs); // imitate image processing > send(childTid, v); UFCS makes it nicer: childTid.send(v); > > } > writeln("main is done."); > } > > static void spawnedFunc(Tid ownerTid) To repeat, you already have a valid ownerTid in this thread. Just remove the parameter. > { > receive((int v){ > Thread.sleep(1500.msecs); I think you should sleep less than that to work at the exact expected time. Otherwise, an unknown amount of time has already passed when this thread is woken up again. Instead of sleeping 1500, something like this may be needed: - This thread looks at the time to figure out how long to sleep e.g. sometimes 1400 msecs - Sleeps that amount - Fires when it wakes up However, you can not expect to be waken up exactly at 1400 msecs later. If timing precision is really important, I recommend running some statistics to see how much off your thread is when it wakes up. Depending on the statistics, I would sleep less than the expected amount and then burn the CPU until it's the exact time. But maybe precision is not that important; so, forget that idea. :) > writeln(v); > }); > } One more thing: It is common for the workers to die with an exception (sometimes with Error). You must catch it (including Error) by the worker thread and report it somehow e.g. with a special exception. Otherwise, nobody will know what happened. This reminds me: If you start the worker with spawnLinked() instead of spawn(), the owner will get a LinkTerminated message if a thread dies. That's another way of detecting that failure. Ali
Re: A scheduled control signal with fibers?
On 9/27/20 3:06 AM, Ferhat Kurtulmuş wrote: > __gshared DList!Entry queue; > __gshared bool shouldRun = true; Have you considered passing messages with std.concurrency.send() and std.concurrency.receive() and friends? You wouldn't need 'queue' because all of your threads already have mail boxes to send messages to each other. > void worker() { > while(shouldRun){ > auto r = queue[]; > if(!r.empty && queue.back.st < Clock.currTime){ > writeln(queue.back); // consume the value > sendPWMSignalToValfe(pwmval) > queue.popLastOf(r); > } > } > } It's not clear whether it's only in your test code but busy-waiting like that will make your CPU very warm. :) Since requests cannot pass each other, your worker thread should have something like the following in that loop: import core.thread; Thread.sleep(duration); Depending on how accurate the operating system honors your sleep requests (e.g. is it real-time?), you may want to sleep less than 'duration' and then busy-wait the rest of the duration. Similar to the difference between spinForce() and yieldForce() of std.parallelism (I understand that your solution should not involve std.parallelism): https://dlang.org/phobos/std_parallelism.html#.Task.spinForce As an improvement when defining durations, you don't need to "hide" units in comments: // enum afterNmilliseconds = 1500; // Instead: enum after = 1500.msecs; msecs and friends are defined in core.time: https://dlang.org/phobos/core_time.html#.dur Ali
Re: Timeout around function call
On 9/23/20 1:19 PM, Imperatorn wrote: > No. You should not share anything. Personally I would just send a > message to request termination or use the solution provided with timeout. std.concurrency does not allow "mutable thread-local data"; so one needs to cast to shared (assuming copying is not desired e.g. because it's expensive). I am modifying my second program[1] with these changes: The worker's receive() call mentions an element with shared ints: receive( // .. same as before // New message type: (shared(int)[] arr) { ownerTid.send(arr[0]); } ); The sender casts to shared and receives a shared(int): auto arr = new int[100]; worker.send(cast(shared)arr); writefln!"Received array result: %s"(receiveOnly!(shared(int))()); It is unfortunate that receiveOnly!int does not work because the returned int is just a copy. Well, at least we have a way of distinguishing int from shared(int). Is it useful? Ali [1] https://forum.dlang.org/post/rkdrql$2uht$1...@digitalmars.com
Re: Array of Algebraic argument syntax
On 9/22/20 2:53 PM, Kasra Sadeghi wrote: On Tuesday, 22 September 2020 at 21:36:48 UTC, Ali Çehreli wrote: ... alias Value = Algebraic!(int, double, string, None); ... void main() { printValue([Value(4.5), Value("hello"), Value(42)]); } Thanks! Wish there was a less redundant syntax for the arrays. Do you really need to write literal Value arrays? If not, you would build a Value[] at runtime without seeing the syntax above. Still, here is a function template that provides better syntax: Value[] valueArray(Args...)(Args args) { Value[] result; foreach (arg; args) { result ~= Value(arg); } return result; } void main() { printValue(valueArray(4.5, "hello", 42)); } Ali
Re: Timeout around function call
On 9/22/20 2:32 AM, drathier wrote:> What's the obvious way to put a timeout around a function call? I'm > thinking a 5 or 30 second timeout, and I'm expecting it to pretty much > never time out. I would start a thread and use receiveTimeout(): import std.concurrency; import std.stdio; import std.exception; import core.thread; // Uncomment to see what happens upon time out. // version = doTimeout; void compute(int i) { version (doTimeout) { writeln("The thread is napping."); Thread.sleep(2.seconds); } ownerTid.send(i + 1); } void main() { auto worker = spawn(, 42); const received = receiveTimeout( 1.seconds, (int result) { writefln!"Received the result: %s"(result); } ); enforce(received, "Timed out."); } The thread need not be one-shot: It can continue waiting for more messages until told to stop: import std.concurrency; import std.stdio; import std.exception; import core.thread; // Uncomment to see what happens upon time out. // version = doTimeout; struct Done { } void computer() { bool done = false; while (!done) { receive( (Done _) { done = true; }, (int i) { version (doTimeout) { writeln("The thread is napping."); Thread.sleep(2.seconds); } ownerTid.send(i + 1); } ); } } void main() { // This time we use spawnLinked() so that we will receive // a LinkTerminated message. And the name is different and // the argument will be passed later with send(). auto worker = spawnLinked(); foreach (i; 0 .. 10) { worker.send(i); const received = receiveTimeout( 1.seconds, (int result) { writefln!"Received the result: %s"(result); } ); enforce(received, "Timed out."); } // Tell worker to stop. worker.send(Done()); // Wait for worker to terminate. receiveOnly!LinkTerminated(); } Ali
Re: Array of Algebraic argument syntax
On 9/22/20 2:30 PM, Kasra Sadeghi wrote: Hi everyone! What's the syntax for passing an array of Algebraics? definition: class None {} class Value = Algebraic!(int, double, string, None); That should be 'alias' instead of 'class': import std.variant; import std.stdio; class None {} alias Value = Algebraic!(int, double, string, None); void printValue(Value[] values) { foreach(value; values) { value.writeln; } } void main() { printValue([Value(4.5), Value("hello"), Value(42)]); } Ali
Re: QuickSort on ranges
On 9/12/20 11:25 AM, jerome wrote: > > import std.stdio : writeln; > import std.algorithm.sorting; > > pure void quickSort(T) (T[] r) > { >if (r.length > 1) >{ > size_t p = pivotPartition(r, r.length-1); //r[$-1] is swapped to r[p] > > quickSort( r[ 0..p ] ); > quickSort( r[ p+1..$ ] ); >} > } > > void main() > { >int[] arr = [9,7, 4 , 8, 5, 3, 1]; >quickSort!(int)(arr); // No need to specify int there because it's deduced from // the parameter. Pretty cool: :) quickSort(arr); >writeln("arr : ", arr ); > > } > > > I spent some time understanding "ranges", but at the end I am surprised > I didn't use them. At the beginning I wrote something like quickSort( > Range r ) and tried randomaccessrange etc but I didn't manage to make it > work. Agreed. The most common range type is InputRange and most algorithms don't require more than that. Combined with slices being the most common RandomAccessRange, it's not obvious why one needs to write algorithms that require RandomAccessRange. So, your algorithm is very useful already but as you said, it can't work with all RandomAccessRanges: import std.range; auto arr2 = iota(5).array; quickSort(chain(arr, arr2));// <-- Compilation error chain() is a very smart algorithm that return a range type that can be a RandomAccessRange if all the ranges given to it are RandomAccessRanges. (Pretty awesome and very practical that we can write ranges like chain() in D!) So, to make your algorithm with any RandomAccessRange, we need to change it like this: pure void quickSort(R) (R r)// <-- The only change Now the quickSort(chain(arr, arr2)) expression can be compiled and the result is awesome too: // Wow! Your quickSort operated on the elements of two // separate ranges! :) writeln(arr); writeln(arr2); Optionally, you can put a template constraint on your algorithm to communicate the fact that it can only work with RandomAccessRanges: import std.range : isRandomAccessRange; pure void quickSort(R) (R r) if (isRandomAccessRange!R)// <-- Here { // ... } Doing that moves potential compilation errors from your algorithm to the caller. For example, if they call your algorithm with int[string], they will get a compilation error saying "you can't call this function with int[string]". Ali
Re: how to do this meta-programming? print the address of random element's address of a variable length of arrays?
On 9/11/20 6:44 PM, mw wrote:> e.g. > > int[] a = new int[la]; > int[] b = new int[lb]; > int[] c = new int[lc]; > int[] d = new int[ld]; > > > the func I want to write, e.g. for 2 arrays (instantiation) is like this: > > void print_random_elem_addr(int[] x, int[] y) { >auto i = random_int_between(0, x.length); >auto j = random_int_between(0, y.length); >print(&(x[i], &(y[j])); // only single print() func call allowed! > } > > > But I want one generic function, which can be called as: > > print_random_elem_addr(a, b); > print_random_elem_addr(a, b, c); > print_random_elem_addr(a, b, c, d); If they are all of same type like int[] in this case, then you can variable number of parameters, which means "any number of int[] arrays" below, elements of which can be called either as separate arguments or as a single array argument: import std.stdio; import std.random; void print_random_elem_addr(int[][] arrays...) { foreach (i, array; arrays) { const chosen = uniform(0, array.length); writefln!"Array %s, element %s: %s"(i, chosen, [chosen]); } } void main() { auto randomLengthArray() { return new int[uniform(1, 101)]; } auto a = randomLengthArray(); auto b = randomLengthArray(); auto c = randomLengthArray(); writeln("As independent arguments:"); print_random_elem_addr(a, b, c); writeln("As a single argument:"); print_random_elem_addr([a, b, c]); } Warning: The array that is automatically generated by the first print_random_elem_addr() call in main() is short-lived: You cannot store a slice of it because the array that contains the arguments may be destroyed upon leaving the function (e.g. in the "independent" case above). Here is some more information: http://ddili.org/ders/d.en/parameter_flexibility.html#ix_parameter_flexibility.variadic%20function There are other ways of doing the same thing. For example, if you want to work with different ranges, you can use tuple template parameters: http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.tuple%20template%20parameter Ali
Reducing .init effect of a struct that has large static array members
[tldr; I have come up with a way of removing all undesired effects of large static array struct members. See conclusion at the bottom.] Continuing the discussion at https://forum.dlang.org/thread/rdk3m2$725$1...@digitalmars.com and understanding kinke's comments there better... And this is all with dmd... 1) Assuming that static array members are really required in the program, the following definition is not desirable because S.init is embedded into the binary image as 8000 bytes (I have much bigger ones in the wild): struct S { double[1000] a; } static assert (S.init.sizeof == 8000); // That S.init is embedded into the binary One way of proving that S.init is indeed embedded into the binary is running obj2asm that is shipped with dmd: 'obj2asm deneme.o') So, that is not good. 2) In order to remove that huge S.init from the program, one can initialize the member with '= void': struct S { double[1000] a = void; } pragma(msg, S.init); // <-- Aside: As a side effect, this output is // now just "S()" and does not include // an array of 1000 elements. Although now the binary does not contain an S.init of 8000 bytes, it contains CPU instructions to set 1000 elements: xor EAX,EAX mov 0E0C0h[RBP],EAX mov 0E0C4h[RBP],EAX [... many more to set all elements ...] WAT!!! :) That is not good either because now the compiled code is large. (I think and hope other compilers use memset() here.) As explained in that earlier thread and as seen above, contrary to spec (perhaps to an earlier spec?) and fortunately, '= void' does not "leave the elements uninitialized" but the elements are now 0.0. So, that's doubly [pun] bad: The code is large and the elements are not double.nan. 3) To remove that huge struct initialization code, one can @disable the default constructor. And to provide double.nan values, one can provide a function; which may be named specially, or marked with a UDA or some other way. Below, I use a constructor that takes a special type to mark that this is my "default constructor": struct DefaultCtor {}// <-- My special "marker" struct S { double[1000] a = void; @disable this(); this(DefaultCtor) {// <-- My "default constructor" a[] = double.init; // <-- Good: not 0.0 anymore } } void main() { auto s = S(DefaultCtor());// <-- But now the syntax is ugly import std; assert(s.a[42].isNaN); } 4) CONCLUSION: The following 'defaulted' template makes the syntax acceptable as well at least for Ali: struct DefaultCtor {} // Special type used as a user-defined UDA ;) struct S { double[1000] a = void; // To not embed S.init into the binary @disable this();// To not generate many CPU instructions this(DefaultCtor) { // My "default constructor". (This could a[] = double.init;// be a template to not even need a // theoretical rvalue parameter.) } } template defaulted(T) { // Generic template for my default constructor syntax enum defaulted = { return T(DefaultCtor()); }(); } void main() { auto s = defaulted!S; // My default construction syntax } That method works for me. Am I missing something? Ali
Re: how stdin stream works?
On 8/19/20 11:46 AM, Flade wrote: Try instead getting a line via readln, and then trying to read that into your expected input. -Steve Thanks Steve! I will get the input a string then as you said and then I'll try to convert it! Thanks a lot, have a nice day! In some cases clearerr() and readln() may be what is needed: import std.stdio; void main() { int x; bool accepted = false; while (!accepted) { try { write("x: "); readf(" %d", x); accepted = true; } catch (Exception msg) { writeln("Please give a right coordinate"); stdin.clearerr(); stdin.readln(); } } writeln("x is ", x); } Note that I used " %d" because "%d/n" would not clean when nothing was input by just hitting the Enter key. A space character in the format string means "read and ignore any whitespace at this point" and I like it. :) Also note I changed the name of the variable as 'accepted'. :) Ali
Re: Disjoint slices of an array as reference
On 8/19/20 9:11 PM, data pulverizer wrote: On Thursday, 20 August 2020 at 03:47:15 UTC, Paul Backus wrote: double[][] y; y ~= x[0..5]; Thanks. I might go for a design like this: ``` struct View(T){ T* data; long[2][] ranges; } ``` The ranges are were the slices are stored and T* (maybe even immutable(T*)) is a pointer is to the start of the original array. I'll use an opIndex that calculates the correct index in the original array to obtain the right data. I implemented the same idea recently; it's a fun exercise. :) I didn't bother with opIndex because my use case was happy with just the InputRange primitives (and .length I think). And I had to implement it because std.range.chain works only with statically known number of sub-ranges. :/ If the number of ranges are known, then this works: import std.stdio; import std.range; void main() { auto x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; auto y = chain(x[0..5], x[9..14]); writeln(y); } [1, 2, 3, 4, 5, 10, 11, 12, 13, 14] Ali
Re: Disjoint slices of an array as reference
On 8/19/20 7:40 PM, data pulverizer wrote: > An array in D is either two pointers or one pointer and a length (I > don't know which) It is the length, followed by the pointer, equivalent of the following struct: struct A { size_t length_; void * ptr; size_t length() { return length_; } size_t length(size_t newLength) { // Modify length_ and ptr as necessary } } Ali
Re: Factory pattern for classes
On 8/10/20 8:38 AM, lexxn wrote: Btw is it possible to pass a property to the constructor, if I've one declared, in the factory? I'm talking about this piece cast(A)Object.factory("deneme.A") I think you mean "parameter". No, Object.factory creates the object with its default constructor. Ali
Re: generating random numbers
On 8/9/20 10:51 PM, Andy Balba wrote: generating random numbers using https://dlang.org/library/std/random/uniform01.html I find the example given in this section totally incomprehensible ... Can any help me answer two simple questions: How to generate a random floating number in range [0,1) ? How to set a seed value, prior to generating random values ? I think feqrel() is the confusing and unnecessary part there. The following is all you need: import std.stdio; import std.random; void main() { auto rnd = MinstdRand0(42); // <-- Seed foreach (i; 0 .. 10) { writeln(rnd.uniform01()); } } feqrel, defined at https://dlang.org/phobos/std_math.html#.feqrel is used to prove that the first two floating point values generated are equal to 0.000328707 and 0.524587. (Check out the return value of feqrel, which is used in assert statements there to prove that the numbers are "equal" to those.) Ali
Re: Factory pattern for classes
On 8/9/20 7:27 AM, lexxn wrote: > I assume that the correct syntax for the getClassById is > Object getClassById(uint id) { > if (id == 0) { > return new A(); > } else if (id == 1) { > return new B(); > } else { > return new C(); > } > } > or maybe I'm wrong. Because those example classes are not a part of a hierarchy, their common interface is Object. That is the only way to get the code compile. > This way if I try auto myClass = getClassById(0) and > if I've a method in A,B classes when I try to call it with myClass I > get no property methodName for type object.Object. If methodName() is a virtual function of your hierarchy, then normally it is a part of an interface that all those classes implement and the return type is that common ancestor. Here is a working example: module deneme; import std.stdio; interface I { void methodName(); } class A : I { void methodName() { writeln("A"); } } class B : I { void methodName() { writeln("B"); } } class C : I { void methodName() { writeln("C"); } } I getClassById(uint id) { if (id == 0) { return cast(A)Object.factory("deneme.A"); } else if(id == 1) { return cast(B)Object.factory("deneme.B"); } else { return cast(C)Object.factory("deneme.C"); } } void main() { auto o = getClassById(1); o.methodName(); } Ali
Re: Non-recursive maxSizeOf
On 8/6/20 4:44 AM, Per Nordlöw wrote: On Thursday, 6 August 2020 at 01:13:28 UTC, Ali Çehreli wrote: Boring in D. :p template maxSizeOf(T...) { enum maxSizeOf = compute(); auto compute() { size_t result; static foreach (t; T) { if (t.sizeof > result) { result = t.sizeof; } } return result; } } Thanks. I'm gonna benchmark this against my templated solution. I guess an anonymous function would remove the need for that creative name. :) enum maxSizeOf = { // ... }(); Ali
Re: Non-recursive maxSizeOf
On 8/5/20 5:58 PM, Per Nordlöw wrote: Is it possible to implement template maxSizeOf(T...) { static if (T.length == 1) enum size_t maxSizeOf = T[0].sizeof; else { enum size_t firstSize = T[0].sizeof; enum size_t maxSizeRest = maxSizeOf!(T[1 .. $]); enum size_t maxSizeOf = firstSize >= maxSizeRest ? firstSize : maxSizeRest; } } in a non-recursive way? Boring in D. :p template maxSizeOf(T...) { enum maxSizeOf = compute(); auto compute() { size_t result; static foreach (t; T) { if (t.sizeof > result) { result = t.sizeof; } } return result; } } void main() { pragma(msg, maxSizeOf!(double, char, string)); } Ali
Re: Question about UDAs
On 8/2/20 8:00 PM, Cecil Ward wrote: > Ali Çehreli’s book mentions them briefly with an example > but that doesn’t seem to qualify as a realistic use-case. The XML example I chose there qualifies as serialization like H. S. Teoh mentions. UDAs on user-defined type members are for marking them for later introspection in use cases like "do this for all members but take UDAs into account." For example, the UDA in my example contributes as "serialize all members as XML but obfuscate the members that have a special UDA." UDAs were added to D by a request from Manu Evans and that's when I learned them. In one of Manu's use cases they would put a @Tweakable attribute to certain struct members. The effect of that attribute would be to compile special code that would expose that member in a dialog box where the developer would "tweak" its value to see how the program (a game) would behave at specific values of that member. The awesomeness comes from the fact that once they have this @Tweakable machinery, they don't change their code at all: They put that attribute to certain members during development, find good values and then remove it; perhaps in half an hour. The only addition to code is one @Tweakable attribute and some magic produces a dialog box; then they remove the attribute. Pretty cool. :) Manu's presentatian is available here: https://www.youtube.com/watch?v=FKceA691Wcg Slide 25 at minute 18:30 is one spot he talks about it. Ali
Re: 2-D array initialization
On 8/1/20 7:00 PM, Andy Balba wrote: >> >> ubyte[3][4] c = [ [5, 5, 5], [15, 15,15], [25, 25,25], [35, >> 35,35] ]; > Although not detailed in my original question, in my actual app > I have array ubyte [1000][3] Big which consists of research data I > obtained, > and from which I want to randomly select 4 observations to construct > ubyte c[ ][ ]. It depends on how the data is layed out. Your original question makes me think the data is "code generated" into a D module and that's where you want to initialize that 2D fixed-length (static) array. So, you simply want to import that module in your analysis program: import data; However, I really think the type should be ubyte[3][]. The following option reads the data from a file before analysis. Assuming the data is formatted one ubyte on a line: --- 8< --- 5 5 5 15 15 15 25 25 25 35 35 35 --- 8< --- then the following program does what you want: import std.stdio : File, writefln; import std.algorithm : map; import std.range : array, chunks; import std.string : strip; import std.conv : to; import std.random : choice; auto parseData(string fileName) { return File(fileName) // - Open the file .byLine // - Iterate line-by-line as a range // (WARNING: same line buffer is // shared use byLineCopy if // necessary.) .map!strip // - Strip the element .map!(to!ubyte) // - Convert to ubyte .chunks(3) // - Treat 3 consecutive elements as one // unit .map!(c => c.array) // - Make an array from each chunk ; // NOTE: The returned range object is a chain of // operations to apply on fileName. Nothing will be read // from the file until the returned range is actually // used (i.e. the range is "lazy"). } void main() { auto c = parseData("research_data") // - The lazy range .array; // - As we want to pick // random elements; we // convert the data // range to an // array. This step is // "eager": the entire // file is parsed here. // Demonstrate that the type is a 2D array static assert (is (typeof(c) == ubyte[][])); // The rest is a random choice from that array: foreach (_; 0 .. 10) { auto chosen = c.choice; writefln!"chosen: %s"(chosen); } } If the three ubytes should actually be used as parts of a struct like Color, here is another approach: import std.stdio; import std.algorithm; import std.range; import std.string; import std.conv; import std.random; struct Color { ubyte r; ubyte g; ubyte b; } // Assumes data is one ubyte per line auto parseData(string fileName) { return File(fileName) .byLine .map!strip .map!(to!ubyte); } auto makeColors(R)(R range) { Color[] colors; while (!range.empty) { ubyte pop() { auto value = range.front; range.popFront(); return value; } auto r = pop(); auto g = pop(); auto b = pop(); colors ~= Color(r, g, b); } return colors; } void main() { auto data = parseData("research_data"); auto c = makeColors(data); writefln!"data:\n%(%s\n%)"(c); foreach (_; 0 .. 10) { auto chosen = c.choice; writefln!"chosen: %s"(chosen); } } Sorry my liberal use of 'auto', which hides types. You can define 'c' with explicit types like Color[], or you can expose a variable's type at compile time with pragma(msg): pragma(msg, "the type: ", typeof(c)); That prints Color[] for the second program above. Ali
Re: 2-D array initialization
On 8/1/20 12:57 PM, Andy Balba wrote: > On Saturday, 1 August 2020 at 00:08:33 UTC, MoonlightSentinel wrote: >> On Friday, 31 July 2020 at 23:42:45 UTC, Andy Balba wrote: >>> How does one initialize c in D ? >> >> ubyte[3][4] c = [ [5, 5, 5], [15, 15,15], [25, 25,25], [35, 35,35] ]; > I'm a D newbie. moving over from C/C++, and I'm really finding it hard > to adjusting to D syntax, which I find somewhat cryptic compared to C/C++. That's surprising to me. I came from C++03 year ago but everything in D was much better for me. :) I wanted to respond to your question yesterday and started typing some code but then I decided to ask first: Do you really need a static array? Otherwise, the following is a quite usable 2D array: ubyte[][] c = [ [5, 5, 5], [15, 15,15], [25, 25,25], [35, 35,35] ]; However, that's quite different from a ubyte[3][4] static array because 'c' above can be represented like the following graph in memory. (Sorry if this is already known to you.) c.ptr --> | .ptr | .ptr | .ptr | .ptr | | | | | . . | --> | 35 | 35 | 35 | 35 | etc. etc. --> | 25 | 25 | 25 | 25 | In other words, each element is reached through 2 dereferences in memory. On the other hand, a static array consists of nothing but the elements in memory. So, a ubyte[3][4] would be the following elements in memory: | 5 | 5 | ... | 35 | 35 | One big difference is that static arrays are value types, meaning that all elements are copied e.g. as arguments during function calls. On the other hand, slices are copied just as fat pointers (ptr+length pair), hence have reference semantics. Here are some ways of initializing a static array. This one is the most natural one: ubyte[3][4] c = [ [5, 5, 5], [15, 15,15], [25, 25,25], [35, 35,35] ]; Yes, that works! :) Why did you need to cast to begin with? One reason may be you had a value that could not fit in a ubyte so the compiler did not agree. (?) This one casts a 1D array as the desired type: ubyte[3][4] c = *cast(ubyte[3][4]*)(cast(ubyte[])[ 5, 5, 5, 15, 15, 15, 25, 25, 25, 35, 35, 35 ]).ptr; The inner cast is required because 5 etc. are ints by-default. There is std.array.staticArray as well but I haven't used it. Ali
Re: dynamic array .length vs .reserve - what's the difference?
On 7/30/20 4:42 PM, wjoe wrote: > So .capacity can't be assigned a value like length to reserve the RAM ? Yes, a read-only property... >> auto a = b; >> b = b[0 .. $-1]; >> b ~= someT; >> >> If that last line is done in-place, then it overwrites a[$-1]. > > So this is a case of sharing being terminated ? Yes but the "sharing being terminated" phrase was my attempt at explaining things, which did not catch on. :) > Expired structs are put back into (appended to) the array for reuse. > When the length of the array == 0, upon releasing a struct, this array > is reallocated which isn't supposed to happen. It should just grow like > it did with length > 1. > assumeSafeAppend should accomplish that :) Yes, assumeSafeAppend is exactly for cases like that and it helps. Another option, which is curiously said to be more performant in memory allocation than native arrays, is std.array.Appender. I've used function-local static Appenders to cut down on memory allocation. Here is an uncompiled pseudo code: void foo() { static Appender!int a; a.clear(); // <- Clear state from last execution of this function. //'a' still holds on to its memory. while (someCondition()) { a ~= 42; } // Use 'a' here } So, 'a' will have the longest length ever used up to this point, which may be exactly what is desired. The cool thing is, because data is thread-local by-default in D, every thread gets their own copy of 'a', so there is not danger of data race. :) (Warning: Don't call foo() recursively though. ;) ) Ali
Re: dynamic array .length vs .reserve - what's the difference?
On 7/30/20 8:58 AM, wjoe wrote: b.reserve(n); b.length = n; There may be something that I don't know but I think assigning to the .length property alone should be the same as reserving and then assigning. reserve is supposed to make sure no memory will be allocated as elements are added. capacity tells how many elements can be added without memory is allocated. However, the D runtime does its best to elide actual memory allocation if there is room beyond the array's last element and it's safe to do so. This article is considered a must-read for understanding what is going on behind the scenes: https://dlang.org/articles/d-array-article.html I tried to introduce the concept of slices "sharing elements" as well as how .capacity is used to determine whether sharing will be terminated, here: http://ddili.org/ders/d.en/slices.html#ix_slices..capacity Ali
Re: is using predSwitch the only way to create to create recursive functions in D ?
On 7/29/20 3:13 PM, Andy Balba wrote: ,, Not at all. The wording in the documentation is misleading. Recursive functions are as trivial as they are: int foo(uint i) { if (i == 0) { return 42; } return foo(i - 1); } void main() { assert(foo(7) == 42); } Ali
Re: Using D within a rust codebase
On 7/27/20 4:43 AM, Ali Çehreli wrote: On 7/27/20 3:50 AM, Jacob Carlborg wrote:> On 2020-07-27 03:03, Paul > The D runtime needs to be initialized first [1]. Then it should be > terminated as well [2]. > > [1] https://dlang.org/phobos/core_runtime.html#.rt_init [...] pragma (crt_constructor) extern (C) int lib_init() { return Runtime.initialize() ? 0 : 1; } Ok, now I learned that my bool-to-int conversion is already taken care of by rt_init(). Cool. :) Ali
Re: Using D within a rust codebase
On 7/27/20 3:50 AM, Jacob Carlborg wrote:> On 2020-07-27 03:03, Paul Backus wrote: > >> extern(C) void hello() >> { >> import std.stdio: writeln; >> writeln("Hello from D!"); >> } > > The D runtime needs to be initialized first [1]. Then it should be > terminated as well [2]. > > [1] https://dlang.org/phobos/core_runtime.html#.rt_init > [2] https://dlang.org/phobos/core_runtime.html#.rt_term > They should be taken care of when the program is linked with a D compiler. Otherwise, e.g. when the extern(C) code is part of a library written in D, one way of doing it is to add the following two functions to the library. (Typing by hand; may have typos). import core.runtime; pragma (crt_constructor) extern (C) int lib_init() { return Runtime.initialize() ? 0 : 1; } pragma (crt_destructor) extern (C) int lib_deinit() { return Runtime.terminate() ? 0 : 1; } Ali
Re: miscellaneous array questions...
On 7/20/20 8:16 PM, a...@a.com wrote: >> 3) Lastly, In the following code snippet, is arrayA and arrayB both >> allocated on the stack? arrayA is allocated on thread-local storage and lives as long as the program is active. I guess a final interaction with it can be in a 'static ~this()' or a 'shared static ~this()' block. Note that this is different from e.g. C++: In that language, arrayA would be a "global" variable and there would be a single instance of it. In D, there will be as many arrayA variables as there are active threads. (One thread's modification to its own arrayA is not seen by other threads.) arrayB is allocated on the stack and lives as long as the scope that it is defined inside. That scope is main's body in your code. > And how does their scopes and/or lifetimes >> differ? >> >> module1 = >> int[100] arrayA; >> void main() >> { >> int[100] arrayB; >> // ... >> } >> module1 = Ali
Re: How can I make executeShell ask for Admin Elevation?
On 7/11/20 7:10 PM, Marcone wrote: I don't want start program with admin elevation, but ask user for admin permission when some function is called. Here is a hacky solution that attempts the command and fails back to asking the password. It should work on POSIX systems. (Tested on Linux.) import std.stdio; import std.process; import std.format; import std.algorithm; // Copied the interface from executeShell auto executeShellSudo(scope const(char)[] command, const string[string] env = null, Config config = Config.none, size_t maxOutput = size_t.max, scope const(char)[] workDir = null, string shellPath = nativeShell) { // First assume the user is super user: auto suCommand = format!"sudo --non-interactive %s"(command); auto execute() { return executeShell(suCommand, env, config, maxOutput, workDir, shellPath); } auto result = execute(); if ((result.status == 1) && (result.output == "sudo: a password is required\n")) { // Have sudo ask for password. (Alternatively, sudo can be invoked // with the --askpass switch.) suCommand = format!"sudo %s"(command); result = execute(); } return result; } void main() { auto result = executeShellSudo("cat /dev/null"); writeln(result); } Ali
Re: What's the point of static arrays ?
On 7/10/20 8:03 AM, wjoe wrote: > What I'm saying is even if this allocation is slow let's say 5ms, but it > only happens once, that wouldn't matter to overall performance at all. Yes, you are correct and there are dynamic arrays that are allocated once in many programs. I haven't read the rest of your post but you've said elsewhere that a static array is on the stack. Yes, there are such static arrays but the issue is not that simple. struct S { float[3] rgb; // Can be on the stack or dynamic memory } The member of that struct can be anywhere: void foo() { S s;// On the stack auto arr = [ S() ]; // On dynamically allocated memory } Additionally, as is common and understandable in D, we are conflating dynamic arrays and slices. The way I see it is dynamic array is owned by the D runtime. Although a slice is an interface to such dynamic arrays, a slice can start its life with non-dynamic arrays and may or may not move to accessing dynamic arrays. struct S { float[] arr; // A slice can use dynamic or static memory } void foo() { float[10] storage; auto a = S(storage[1..7]); // Slice is referring to the stack space auto b = S(); b.arr ~= 1.5; // Slice is referring to dynamic memory } What is important is overhead: 1) Allocation: Only sometimes an issue. 2) Cost of the slice object (1 pointer and 1 size_t): The cost of this may be enormous. (Compare the 12-byte rgb above to a 16-byte slice overhead.) 3) Cost of accessing the elements: The access through that extra level of indirection may be a cost but the CPU can alleviate it by pre-fetching or caching but only for some access patterns. 4) Bounds checking: Some bounds checks for static arrays can be elided at run time. So, there are cases where a dynamic array is better (or must), there are cases there is no winner and there are cases where a static array is a huge win. Ali
Re: What's the point of static arrays ?
On 7/9/20 5:12 AM, wjoe wrote: Considering the many downsides why would I ever want to choose a static over a dynamic array ? In addition to what others said, dynamic arrays can be more expensive both in space and time. Time: Dynamic array elements are accessed through an extra pointer compared to static arrays. Depending on the usage pattern of the data, that extra indirection may be slower (e.g. due to the extra load on the CPU's cache). Space: Every dynamic array is represented by the pair of one pointer (void*) one length (size_t) e.g. 2 * 8 = 16 bytes on a 64-bit system. Assuming the array is just 3 floats, which is a common type used for RGB, 3D coordinates, etc. (3 * 4 = 12 bytes), then those 16 bytes are more than the data itself. I wrote the following program (as a fun morning exercise, before coffee :o) ) to display bytes used by different kinds of variables: import std.stdio; import std.range; import std.algorithm; import std.traits; size_t bytesUsed(T)(T var) { static if (isDynamicArray!T) { enum dynamicArrayOverhead = (void[]).sizeof; // Double check: static assert (dynamicArrayOverhead == size_t.sizeof + (void*).sizeof); return dynamicArrayOverhead + var.map!(element => bytesUsed(element)).sum; } else static if (isAssociativeArray!T) { static assert (false, "I don't know the implementation of AAs."); } else static if (is (T == struct)) { // BUG: Ignores alignment size_t total; foreach (member; var.tupleof) { total += bytesUsed(member); } return total; } else static if (is (T == class)) { // BUG: Ignores alignment size_t total; foreach (member; var.tupleof) { total += bytesUsed(member); } enum classOverhead = (void*).sizeof * 2; return classOverhead + total; } else { return var.sizeof; } // BUG: union? } unittest { struct S { int[] arr; void* ptr; } assert(bytesUsed(S([1, 2, 3])) == size_t.sizeof + (void*).sizeof + 3 * int.sizeof + 8); } void info(alias var)() { writefln!"'%s' is %s and uses %s bytes."(var.stringof, typeof(var).stringof, bytesUsed(var)); } void main() { // This is an efficient data structure: alias Color = float[3]; // red, green, blue alias DayColors = Color[7]; // Comparing it to the dynamic array equivalent: DayColors a; auto b = makeDayColors(); info!a; info!b; } float[] makeColor() { // Syntax confusion alert: Return type is *not* a static array. :/ return new float[3]; } float[][] makeDayColors() { float[][] result = new float[][7]; foreach (ref e; result) { e = makeColor(); } return result; } Ali
Re: Template function specialization doesn't work
On 7/7/20 12:53 PM, IGotD- wrote: ubyte[3] ar = [ 1, 2, 3 ]; ubyte[] arSlice = ar; overloadedFunction(arSlice); The first function will be used. Shouldn't the template argument (T : T[]) make the compiler pick the second one? There is also template constraints which may be useful: import std.traits; void overloadedFunction(T)(ref T val) if (!isArray!T) { writeln("general"); } void overloadedFunction(T)(ref T s) if (isArray!T) { writeln("T[]"); } Ali
Re: opApply and attributes
On 7/6/20 5:20 PM, solidstate1991 wrote:> See implementation of data structure here: > https://github.com/ZILtoid1991/collections-d/blob/master/source/collections/treemap.d#L565 > > > If I try to compile this code, it'll fail, limiting it's usecase: > > @safe pure unittest { > alias IntMap = TreeMap!(int, int, false); > IntMap test; > test[5] = 5; > test[7] = 7; > test[3] = 3; > foreach(elem, key; test) { > assert(elem == key); > } > } I am not sure whether I understand it correctly but there has been a request for opApply() to gain the attributes of the delegate (or the range?). In other words, "transfer the attributes to opApply". This is needed because I want opApply() to work with any foreach body, attributes of which opApply() cannot know. I am sure I created an issue on Dlang bug tracker for Weka on this topic but I can't find it now. (Aside: The search boxes on the bug tracker are inferior to the automatic search feature that works when creating a bug.) Anyway, this one seems related: https://issues.dlang.org/show_bug.cgi?id=7543 Ali
Re: I need an Easy example to understand Alias This
On 7/6/20 5:44 PM, Marcone wrote: On Tuesday, 7 July 2020 at 00:42:40 UTC, Ali Çehreli wrote: On 7/6/20 5:35 PM, Marcone wrote: Hi, I study Dlang for one year, and I can't understand alias this. I need an Easy example to understand Alias This. Is the following example useful? http://ddili.org/ders/d.en/alias_this.html Ali I can't undestand it. I need a simple example. I find the example of converting two integers to double to be a simple example of 'alias this'. (If it's not simple, then there is another example later.) So, allow me to change the name of the struct. :) Let's say we have a Money class that stores dollars and cents as two separate members. This class also has a member function that returns the amount as double: struct Money { long dollars; long cents; double value() const { return double(cents) / 100 + dollars; } } unittest { assert(Money(10, 50).value == 10.5); } void main() { } So far so good: We can get the value by calling value(). *If* this is a type where conversion to double should be automatic, then calling value() all over the place might be considered cumbersome and too wordy. If that's true, we may want to get the value of this type automatically as double. For example, we may want to be able to call the following function with Money: void foo(double d) { // ... } void main() { foo(Money(20, 50)); // <-- Compilation error } Currently the code fails to compile because Money is not 'double'. (Note: Arguably, Money is not a type that should be converted to double automatically, but again, I find this example simple.) 'alias this' allows a type to be converted to a specific type automatically. For example, if we want to convert Money objects automatically to 'double', then we use the following line inside the struct defition: alias value this; What that line means is this: "Dear compiler, please automatically convert this type to whatever the type of the 'value' member is." In this case, "Allow using an object of Money wherever that object is used in place of a double." So, with that addition, now the call inside main compiles and foo() gets called with 'Money(20, 50).value' (compiler injects an automatic call to value()). Here is the complete program: struct Money { long dollars; long cents; double value() const { return double(cents) / 100 + dollars; } alias value this; // <-- ADDED } unittest { assert(Money(10, 50).value == 10.5); } void foo(double d) { // ... } void main() { foo(Money(20, 50)); } 'alias this' is sometimes used where a type needs to behave like some other type with some added functionality. For example, here is another example where a Month type should behave like an 'int' but it cannot have any value other than 1-12: struct Month { int value; this(int value) { this.value = value; } invariant() { assert(value >= 1); assert(value <= 12); } alias value this; } unittest { import std.exception; assertThrown!Error(Month(0)); assertThrown!Error(Month(13)); void foo(int) { } // 'alias this' allows the following call to foo() assert(__traits(compiles, foo(Month(3; } void main() { } Ali
Re: I need an Easy example to understand Alias This
On 7/6/20 5:35 PM, Marcone wrote: Hi, I study Dlang for one year, and I can't understand alias this. I need an Easy example to understand Alias This. Is the following example useful? http://ddili.org/ders/d.en/alias_this.html Ali
Re: Generating struct .init at run time?
On 7/2/20 10:51 AM, kinke wrote: On Thursday, 2 July 2020 at 16:51:52 UTC, kinke wrote: `= void` for members doesn't work and, I dare say, not work anytime soon if ever. I've quickly checked; `= void` for members has initialize-with-zeros semantics too, so with LDC, it's equivalent to `= 0` but applicable to user-defined types as well. For DMD, `= void` for non-default-zero-initialized members can be used for the same effect. If all members are effectively zero-initialized, the init symbol isn't emitted, and the compiler initializes the whole struct with zeros. With `= 0`, DMD still emits the init symbol into the object file, but doesn't use it (at least not for stack allocations). TLDR: Seems like initializing (all non-default-zero-initialized) members with `= void` is the portable solution to elide the init symbols *and* have the compiler initialize the whole struct with zeros, so a manual memset isn't required. Thank you! I just checked: Even 2.084 behaves the same. I will deal with double.nan, etc. for structs where they matter. Ali
Re: Generating struct .init at run time?
On 7/2/20 3:37 AM, kinke wrote: > On Thursday, 2 July 2020 at 07:51:29 UTC, Ali Çehreli wrote: >> Of course, the solution is to define members with '= void' > > Since when? https://issues.dlang.org/show_bug.cgi?id=11331 and your > https://issues.dlang.org/show_bug.cgi?id=16956 are still open. Wow! I didn't remember that one. According to its date, it was written when I was working for Weka. Apparently, ldc took care of it for them after all. > For recent LDC versions, the 'solution' is to (statically) initialize > the array with zeros, as fully zero-initialized structs don't feature > any explicit .init symbols anymore. What about floating point and char types? Their .init values are not all zeros in D spec. (I don't think this matters in my case but still.) > So you're saying you have a *stack* that can deal with an 800M struct Sorry, my test code was too simplistic. The actual code constructs these objects in dynamic memory for that exact reason. > I don't think a struct should ever be that large, as it can probably > only live on the heap anyway and only passed around by refs. I'd > probably use a thin struct instead, containing and managing a `double[]` > member (or `double[elementCount]*`). Exactly. These structs are code-generated to reflect ROS interface message types. Just like in D, arrays have dynamic/static distinction in ROS so I blindly translated the types to D without remembering this .init issue. The following are the options I am considering: a) Move to ldc b) As you and IGotD- suggest, define all members with '= void' and memset to zero at runtime. (I will decide whether to take care of char and floating point types specially e.g. by setting doubles to NaN; this distinction may not be important in our use case.) Luckily, issue 16956 you mention above does not affect us because these are non-template structs. c) Again, as you say, define static arrays as dynamic arrays, code-generate a default constructor that sets the length to the actual static length, which requires some magic as struct default constructor cannot be defined for structs. d) ? Ali
Re: Generating struct .init at run time?
On 7/2/20 2:37 AM, IGotD- wrote: > what on earth are those extra 800MB? I'm losing my mind. :) Of course it's just 8M. Too many digits for me to handle. :p > Also, this an obvious optimization that can be implemented, that the > program do an initialization loop instead of putting it in the data > segment when the array size is above a certain size and they are > supposed to have the same value. +1 Ali
Generating struct .init at run time?
Normally, struct .init values are known at compile time. Unfortunately, they add to binary size: enum elementCount = 1024 * 1024; struct S { double[elementCount] a; } void main() { S s; assert(typeid(S).initializer.length == double.sizeof * elementCount); assert(typeid(S).initializer.ptr !is null); } Both asserts pass: S.init is 800M and is embedded into the compiled program. Of course, the solution is to define members with '= void': enum elementCount = 1024 * 1024; struct S { double[elementCount] a = void; // <-- HERE } void main() { S s; assert(typeid(S).initializer.length == double.sizeof * elementCount); assert(typeid(S).initializer.ptr is null); } Now the program binary is 800M shorter. (Note .ptr is now null.) Also note that I did NOT use the following syntax because there is a dmd bug: auto s = S(); // Segfaults: https://issues.dlang.org/show_bug.cgi?id=21004 My question is: Is there a function that I can call to initialize 's' to the same .init value that compiler would have used: S sInit; shared static this() { defaultInitValue(); // Does this exist? } I can then use sInit to copy over the bytes of all S objects in the program. (Both the structs and their object instantiations are all code-generated; so there is no usability issue. There are thousands of structs and the current binary size is 2G! :) ) If not, I am planning on writing the equivalent of defaultInitValue() that will zero-init the entire struct and then overwrite float, double, char, wchar, and dchar members with their respective .init values, recursively. Does that make sense? Ali
Re: How to implement Canceleable spawn() from parent
On 7/1/20 2:41 AM, aberba wrote: On Tuesday, 30 June 2020 at 14:43:40 UTC, Steven Schveighoffer wrote: On 6/30/20 10:15 AM, Simen Kjærås wrote: [...] My thinking is I don't want regular consumers using the package to think about the technicality of thread_joinAll() at all. Thinking about putting it in a mixin like: mixin KeepRunning; Or something How about main() starts a thread that starts all the other threads? Then, thread_joinAll() would go inside the non-main :) thread. However, Steve is right: When main() exits, all threads will and should exit. Ali
Re: How to implement Canceleable spawn() from parent
On 6/29/20 4:34 PM, aberba wrote: > So with this, without the Thread.sleep() to block main from exiting, the > spawned thread will terminate immediately. You can call core.thread.thread_joinAll at the end of main. Another way would be to wait for a worker's exit by looking for LinkTerminated but you need to start the thread with spawnLinked: http://ddili.org/ders/d.en/concurrency.html#ix_concurrency.LinkTerminated Ali
Re: How to implement Canceleable spawn() from parent
On 6/28/20 4:08 PM, aberba wrote: So I checked receiveTimeout() when I was looking for what I could use. I wish there was an example in the docs. https://dlang.org/library/std/concurrency/receive_timeout.html I have an example of it: http://ddili.org/ders/d.en/concurrency.html#ix_concurrency.receiveTimeout Ali
Re: foreach iterator with closure
On 6/28/20 9:07 AM, Denis wrote: > * foreach is the actual iterator, Yes. foreach is "lowered" to the following equivalent: for ( ; !range.empty; range.popFront()) { // Use range.front here } A struct can support foreach iteration through its opCall() member function as well. opCall() takes the body of the foreach as a delegate. Because it's a function call, it can take full advantage of the function call stack. This may help with e.g. writing recursive iteration algorithms. http://ddili.org/ders/d.en/foreach_opapply.html#ix_foreach_opapply.opApply > the instantiation of a struct is the > range. Yes. > * When a constructor is not used, the arguments in the call to > instantiate the range (in this case, `hello` in letters(`hello`)) are > mapped sequentially to the member variables in the struct definition > (i.e. to letters.str). Yes, that is a very practical struct feature. I write my structs with as little as needed and provide a constructor only when it is necessary as in your case. > * When a constructor is used, the member variables in the struct > definition are in essence private. Not entirely true. You can still make them public if you want. http://ddili.org/ders/d.en/encapsulation.html > The arguments in the call to > instantiate the range are now mapped directly to the parameters in the > definition of the "this" function. Yes. > * The syntax and conventions for constructors is difficult and > non-intuitive for anyone who hasn't learned Java (or a derivative). C++ uses the name of the class as the constructor: // C++ code struct S { S(); // <-- Constructor S(int); // <-- Another one }; The problem with that syntax is having to rename more than one thing when the name of struct changes e.g. to Q: struct Q { Q(); Q(int); }; And usually in the implementation: Q::Q() {} Q::Q(int) {} D's choice of 'this' is productive. > The > linked document provides a simplified explanation for the "this" > keyword, which is helpful for the first read: > https://docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html. I like searching for keywords in my index. The "this, constructor" here links to the constructor syntax: http://ddili.org/ders/d.en/ix.html > * In some respects, the Java syntax is not very D-like. (For example, it > breaks the well-established convention of "Do not use the same name to > mean two different things".) Yes but it competes with another goal: Change as little code as possible when one thing needs to be changed. This is not only practical but helps with correctness. > However, it does need to be learned, > because it is common in D source code. I like D. :p > Here is the complete revised code for the example (in condensed form): > >import std.stdio; > >struct letters { > > string str; > int pos = 1;// Assign here or in this()) > > this(string param1) {// cf. shadow str >str = param1;// cf. this.str = param1 / this.str = str >writeln(`BEGIN`); } > > char front() { return str[pos]; } > void popFront() { pos ++; } > bool empty() { return pos == str.length; } > > ~this() { writeln("\nEND"); }} > >void main() { > foreach (letter; letters(`hello`)) { >write(letter, ' '); }} > > At this point, I do have one followup question: > > Why is the shadow str + "this.str = str" the more widely used syntax in > D, when the syntax in the code above is unambiguous? Because one needs to come up with names like "param7", "str_", "_str", "s", etc. I like and follow D's standard here. > One possible reason that occurred to me is that "str = param1" might > require additional GC, because they are different names. Not at all because there is not memory allocation at all. strings are implemented as the equivalent of the following struct: struct __D_native_string { size_t length_; char * ptr; // ... } So, the "str = param1" assignment is nothing but two 64 bit data transfer, which can easily by optimized away by the compiler in many cases. > But I wouldn't > think it'd make any difference to the compiler. Yes. :) > > Denis Ali
Re: foreach iterator with closure
On 6/27/20 8:19 PM, Denis wrote: > Is it possible to write an iterator It is arguable whether D's ranges are iterators but if nouns are useful, we call them ranges. :) (Iterators can be written in D as well and then it would really be confusing.) >struct letters { > string str; > int pos = 0; > char front() { return str[pos]; } > void popFront() { pos ++; } > bool empty() { >if (pos == 0) writeln(`BEGIN`); >else if (pos == str.length) writeln("\nEND"); >return pos == str.length; }} > >void main() { > foreach (letter; letters(`hello`)) { >write(letter, ' '); } > writeln(); } > > The obvious problems with this code include: > > (1) The user can pass a second argument, which will set the initial > value of pos. That problem can be solved by a constructor that takes a single string. Your BEGIN code would normally go there as well. And END goes into the destructor: struct letters { this(string str) { this.str = str; this.pos = 0; // Redundant writeln(`BEGIN`); } ~this() { writeln("\nEND"); } // [...] } Note: You may want to either disallow copying of your type or write copy constructor that does the right thing: https://dlang.org/spec/struct.html#struct-copy-constructor However, it's common to construct a range object by a function. The actual range type can be kept as an implementation detail: struct Letters { // Note capital L // ... } auto letters(string str) { // ... return Letters(str); } struct Letter can be a private type of its module or even a nested struct inside letters(), in which case it's called a "Voldemort type". Ali
Re: Passing iterators into functions
Collection elements are accessed by ranges in D. Although both iterators and ranges fundamentally do the same thing (access elements). More accurately, ranges correspond to a pair iterators. On 6/24/20 8:35 PM, repr-man wrote: > auto func(R)(R r, size_t width) > if(isRandomAccessRange!R) > { > return r.chunks(width); > } > > void main() > { > int[5] a = [0, 1, 2, 3, 4]; > int[5] b = [5, 6, 7, 8, 9]; > auto x = func!(int[])(chain(a[], b[]), 5); Is there a reason why you specify the template argument there? > This seems to have to do with the fact that all iterators return their > own unique type. When the element is normally different, there would be no way of using one type anyway. This is similar to how vector::iterator is a different type from e.g. vector::iterator. > Could someone help me understand the reason behind > this design Andrei Alexandrescu has the following article on D's ranges: https://www.informit.com/articles/printerfriendly/1407357 > and how to remedy my situation? Just don't specify the function template argument and it will work. Ali
Re: how to skip the next (n) item & continue from (n+1) with a range ? e.g. in File(fn).byLine();
On 6/22/20 2:37 PM, mw wrote: > On Monday, 22 June 2020 at 20:58:58 UTC, Ali Çehreli wrote: > >> Others have other explanations for this but my understanding is about >> exception safety: If it changed internal state and returned the front >> object, you would no be able to make a function like popFront() >> strongly exception safe. (There are ample documentation for this topic >> in C++ circles.) > > That's one consideration. But, it will be more interesting in knowing > (based on actual usage): > > (a) how many bugs % are due to exception un-safe I am not claiming that strong exception safety is the reason for Phobos design. However, knowing what I know, I would use the same primitive operations. It's the same with e.g. C++ as well: != end(), operator*, operator++. And operator++ does not return the current object either. Even if zero bugs are due to exception un-safe, a library designer would not oversee that knowledge. It is impossible to make an interface strongly exception safe but the reverse is always possible. > (b) how many bugs % are due to front / popFront separation? I made the mistake of forgetting to call popFront() perhaps 10 times and got stuck in an infinite loop and quickly hit a segmentation fault and that was it. > And which is more bug-prone for a typical programmer? my gut feeling is > (b), at least we just saw one in this thread. > > > And > > -- loop thru a static structure content like a simple array, why we need > to worry about exception safe? *If* strong exception guarantee is needed, it doesn't matter whether it's a simple array or not. > -- loop thru dynamically generated content, esp. network or more > external complex structure may worth considering exception safety. But > even there, do people always need to call !range.empty() check first? > when it's not empty, how much more exception un-safety that > popAndReturnFront() can introduce than the combination of `front(); ...; > popFront();"? It has been demonstrated on a Stack type that conflating top() and pop() cannot be made strongly exception safe. It's the same with front() and popFront(). > And why not provide a popAndReturnFront(), and let the user decide based > on his/her own actual usage? Because if the primitives were empty() and popAndReturnFront(), then it wouldn't be made strongly exception safe. With the current primitives of empty(), front(), and popFront(), it's possible to implement popAndReturnFront(). I like the following one that I wrote in three minutes. :) import std.stdio; auto popAndReturnFront(R)(ref R range) { import std.range : empty, front, popFront, ElementType; import std.typecons : Nullable, nullable; if (range.empty) { return Nullable!(ElementType!R)(); } scope (success) range.popFront(); return nullable(range.front); } void main() { auto range = [ 1, 2, 3 ]; while (true) { auto front = range.popAndReturnFront; if (!front.get()) { break; } writeln(front); } } >> Another reason is cohesion: We want functions to have as little >> responsibility as possible (ideally single). > > Again we have to weight which way is more bug-prone, any actual > statistics on the above (a) v.s (b)? I am not aware of any bugs related to the separation of front() and popFront(). Ali
Re: how to skip the next (n) item & continue from (n+1) with a range ? e.g. in File(fn).byLine();
On 6/22/20 1:46 PM, mw wrote: > so `front` is peek, and `popFront` is the pop action whose return type > is `void`, why we need two *separate* calls instead of just let > `popFront` return T Others have other explanations for this but my understanding is about exception safety: If it changed internal state and returned the front object, you would no be able to make a function like popFront() strongly exception safe. (There are ample documentation for this topic in C++ circles.) Another reason is cohesion: We want functions to have as little responsibility as possible (ideally single). > (or do we have another function for this)? There are many useful functions in std.range: https://dlang.org/phobos/std_range.html The "take" and "drop" functions may be useful. Ali
Re: GtkD code review - How to update a progressbar using data sharing concurrency
On 6/21/20 5:52 AM, adnan338 wrote: I am trying to figure out how to prevent this data race. I still like the std.concurrency method I used here: https://forum.dlang.org/post/rkitcprqvslexgqaf...@forum.dlang.org The only difference is that your individual progresses are from 0% to 100%. The example can be changed easily to report 100% once at the end of each download. Ali
Re: Some questions about strings
On 6/21/20 8:17 PM, Denis wrote:> I have a few questions about how strings are stored. > > - First, is there any difference between string, wstring and dstring? string is char[] wstring is wchar[] dstring is dchar[] char is 1 byte: UTF-8 code unit wchar is 2 bytes: UTF-16 code unit dchar is 4 bytes: UTF-32 code unit > For example, a 3-byte Unicode character literal can be assigned to a > variable of any of these types, then printed, etc, without errors. You can reveal some of the mystery by looking at their .length property. Additionally, foreach will visit these types element-by-element: char, wchar, and dchar, respectively. > - Are the characters of a string stored in memory by their Unicode > codepoint(s), as opposed to some other encoding? As UTF encodings; nothing else. > - Assuming that the answer to the first question is "no difference", do > strings always allocate 4 bytes per codepoint? No. They always allocate sufficient bytes to represent the code points in their respective UTF encodings. dstring is the only one where the number of code points equals the number of elements: UTF-32 code units, each being 4 bytes. > - Can a series of codepoints, appropriately padded to the required > width, and terminated by a null character, null character is not required but may be a part of the strings. > be directly assigned to a > string WITHOUT GOING THROUGH A DECODING / ENCODING TRANSLATION? It will go through decoding/encoding. > The last question gets to the heart of what I'd ultimately like to > accomplish and avoid. > > Thanks for your help. There is also the infamous "auto decoding" of Phobos algorithms (which is as a mistake). I think one tool to get away from auto decoding of strings is std.string.representation: https://dlang.org/phobos/std_string.html#.representation Because it returns a type that is not a string, there is not auto decoding to speak of. :) Ali
Re: GtkD code review - How to update a progressbar using data sharing concurrency
On 6/20/20 9:30 AM, adnan338 wrote: > Hello, I need a code review on my strategy I don't know gtkd so I did not compile the code and I did not review the code very carefully. However, I don't think you need to 'synchronized' the whole parallel loop. Since there is only one thread that executes start(), that synchronized cannot have any effect at all. What you want to synchronize is the mutating access to 'completed' by the threads that parallel() starts automatically. So, move 'synchronized' just around that expression: // REMOVE this one: // synchronized // { foreach (_; downloader.links.parallel()) { Thread.sleep(uniform(0, 6, rnd).seconds()); // ADD this one: synchronized { ++cast() downloader.completed; } } // } Ali
Re: "if not" condition check (for data validation)
On 6/18/20 5:13 AM, Denis wrote: > Templates offer a clean syntax Here is an earlier experiment of nested templates, which may be useful in this case. This is unrelated to your problem but the syntax can be pretty readable with templates: // If there are template arguments, then the result is the first of // them. If there is no argument, then the result is the argument // of 'otherwise'. template FirstOf(T...) { template otherwise(alias D) { static if (T.length != 0) { enum otherwise = T[0]; } else { enum otherwise = D; } } } unittest { static assert (FirstOf!(1.5, "hello").otherwise!100 == 1.5); static assert (FirstOf!().otherwise!42 == 42); } auto foo(Args...)() { auto temp = FirstOf!Args.otherwise!1.5; // ... return temp + 0.5; } unittest { assert(foo!(10, int[])() == 10.5); assert(foo() == 2.0); } void main() { } I think you should be able to pass callables as 'alias' template arguments but I couldn't put much thought into it. Ali
Re: "if not" condition check (for data validation)
On 6/17/20 4:46 PM, Denis wrote:> Is there a cleaner way to implement an "if not" condition check? >if ( configfile.isFile && configfile.extension == ".conf", message ) { } >else if (isConfigFile(name)) { // ... } else { // ... } The following is suitable in many cases: enforce(isConfigFile(name), format!"%s is not a config file"(name)); // ... I shortened that in many occasions: enforceConfigFile(name); // ... Of course, depending on the situation it is assert() or assertConfigFile(). Ali
Re: How to create Multi Producer-Single Consumer concurrency
On 6/12/20 3:02 PM, adnan338 wrote: > So there are multiple "download finished" message producers, and one > consumer of those messages. Furthermore, that producer has a callback > that triggers an UI object. That's almost exactly what I do in some of my programs. I use std.concurrency and the following is a working sketch of what I do. I assumed you get finer individual granularity of progress as opposed to the binary 0% -> 100%. import std.stdio; import std.concurrency; import std.algorithm; import std.range; import std.exception; import std.format; import core.thread; struct Progress { Tid tid; // The id of the reporting thread size_t amount;// The amount of progress so far size_t total; // Total progress (can be file size) } void display(Progress[Tid] progresses) { const amount = progresses.byValue.map!(p => p.amount).sum; const total = progresses.byValue.map!(p => p.total).sum; writefln!"%6.2f%%"(100.0 * amount / total); } // The worker thread function void download(string url) { writefln!"Worker %s downloading %s."(thisTid, url); enum total = 20; foreach (i; 0 .. total) { // Imitate some progress Thread.sleep(100.msecs); // Report progress to owner ownerTid.send(Progress(thisTid, i + 1, total)); } } void main() { auto list = [ "dlang.org", "ddili.org" ]; auto downloaders = list.length .iota .map!(i => spawnLinked(, list[i])) .array; Progress[Tid] progresses; size_t finished = 0; while (finished != list.length) { receive( (LinkTerminated arg) { ++finished; // Check whether this thread is exiting prematurely enforce((arg.tid in progresses) && (progresses[arg.tid].amount == progresses[arg.tid].total), format!"Thread %s exited unexpectedly"(arg.tid)); }, (Progress progress) { progresses[progress.tid] = progress; progresses.display(); } ); } writeln("Processing the downloaded files."); } Ali
Re: Initializing an associative array of struct
On 6/14/20 7:43 AM, Denis wrote:> @Kagamin: > > On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote: >> parameters[param]=Parameter(); > > I did not realize that you can use a type on the RHS of an assignment, Note that it's not just the type but with parenthesis after it. For example, Foo() default-constructs an object of Foo. > There does not appear to be a way to loop over the elements of an enum, There is std.traits.EnumMembers: import std.traits; enum Foo { abc, xyz } void main() { foreach (foo; EnumMembers!Foo) { // ... } } Ali
Re: final switch problem
On 6/13/20 9:22 AM, John Chapman wrote: Hmm, compiling with -release makes it work. Not a huge issue, I'll just avoid final switches in debug mode until it's fixed. Thanks. Apparently, it's a known issue: https://issues.dlang.org/show_bug.cgi?id=19548 Ali
Re: Metaprogramming with D
On 6/8/20 7:50 AM, ag0aep6g wrote: https://ddili.org/ders/d.en/literals.html#ix_literals.q%7B%7D Thank you. I am biased but I like my :) index of the book, where all such syntax items appear: https://ddili.org/ders/d.en/ix.html Ali
Re: Metaprogramming with D
On 6/6/20 5:03 PM, FunkyD wrote:> On Saturday, 6 June 2020 at 09:57:36 UTC, Jan Hönig wrote: > D is pretty good for meta-programming. For certain other things it is > terrible. I am glad I don't know enough about other technologies to feel that way. > String mixins simply mix in D code. It lets you build generic D code. > The big problem here is debugging. There is ZERO ability to properly > debug string mixins. "Zero" is too strong an assertion and because of the following, false: dmd -mixin= ... > Well, what it boils down to is writing out the > string mixin and then debugging that. When I compile my program and there is an issue with a string mixin, Emacs opens the mixin file and shows me the compilation there. This is because dmd's error include the exact line in the where my mixin was broken. Not a shiny IDE but still pretty awesome support. > It would be nice if D had a special D code string that the IDE could > interpret properly. I must be misunderstanding you but it must be an IDE limitation because of the following: writeln(q{ void foo() { } }); My IDE gives me syntax highlighting in that string, so it works somehow. > D basically tries to resolve things after the fact so > > R add(T)(T a, T b) > { > return a + b; > } > > this will attempt to + on a and b after the types are known. If they > can't be added then an error will occur, which is usually cryptic for > templates. That's why we use template constraints and in some cases 'static assert' for custom error messages. > The issue in using D should not be made based on it's metaprogramming. I agree. What feature to use usually emerges by itself. For example, when an algorithm is repeated for many types, it is an opportunity for templates. > D, IMO, is not capable of writing sophisticated programs... "Sophisticated" is relative but such strong assertions can be falsified by a single counterexample. For example, Weka's product is very sophisticated and is written in D. And there is nothing extra or missing in D that makes it incapable in that regard. > this is why > you do not see any. I think the fact that many smart programmers are hostage to other languages is a stronger reason. > No one writes large commercial apps in D. False. > There is > not one! False. And again, even if so, that's not because of D, but because of humans. Can you imagine a CTO, say, in Silicon Valley to have guts to bring D instead of C++? With C++, the CTO will never be blamed; but D, he or she can easily be blamed upon failure. Not because of the technologies but because of politics. > The D ecosystems is poorly structured compared to the top > contenders. Agreed but that is not because D is inferior. Again, that's because people happen to be busy with other technologies. > D is good for small apps, utilities, etc. D can be > integrated with other apps though but then one loses some of the meta > capabilities(since they won't translate). What would one technology that is good for small code not work for a larger system? Threads, communication e.g. memory mapped files, etc. are all there. What magical thing would happen and suddenly D won't work beyond a certain limit? If so, is that any different from any other language? Ali
Re: writeln Function while reading a Text File is printing appending text "before text" and "after text" at the same position
On 6/3/20 1:43 PM, BoQsc wrote: Chomp sounds kind of funny hahaha. Also consider strip, stripLeft, and stripRight. (Not because they may be funny but because they are useful as well. :) ) Ali
Re: Making alias of a struct field needs "this".
On 6/2/20 1:56 AM, realhet wrote: > struct A{ >struct B{ int c; } >B b; > >auto f(){ > alias d = b.c; The spec explicitly says it's not legal: "Aliases cannot be used for expressions" (Item 10): https://dlang.org/spec/declaration.html#alias I use nested functions for such cases: auto f(){ auto d() { return b.c; } return d; } Ali
Re: How to efficiently resolve Associative Arrays not being sorted?
On 6/2/20 12:32 AM, BoQsc wrote: > I want to read a file, put it into an array, make some search and > replace on the content and output the modified text. How large is the data? If it fits into memory, just read the whole thing, update it, sort the keys, and then output like this: import std.stdio; import std.algorithm; foreach (key; aa.keys.sort) { writeln(key, aa[key]); } Of course, you can save the sorted array in a local variable as well if you will use it again: auto keys = aa.keys.sort; One great thing about programs that read and write files is that unless the data is so large that it does not fit into physical memory, you can't feel the time cost of that sort operation. :) Ali
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On 5/31/20 1:00 PM, mw wrote:> On Sunday, 31 May 2020 at 09:37:24 UTC, Ali Çehreli wrote: > One question: in Sebastiaan's solution opDispatch is performed at > run-time Templates don't exist at run time. They are used for generating code at compile time and that's it. opDispatch is a template. Like all templates, it's evaluated at compile time and code is generated for it at compile time. However, if opDispatch() is a member function template, then there will be a function call execution at runtime but this is not different from any other member function call. Here is a struct with an opDispatch() used as a member function template. struct XmlElement { static opDispatch(string tag)(string value) { import std.range; import std.format; enum opening = format!"<%s>"(tag); enum closing = format!""(tag); // Note: Although we return a chained range, this could return a // string[3] as well, which may possibly be more performant. return chain(opening, value, closing); } } import std.stdio; void main() { writeln(XmlElement.foo("hello")); writeln(XmlElement.bar("world")); } opDispatch() is instantiated with two strings in the program: "foo" and "bar". As a result, the XmlElement struct will be the equivalent of the following one: struct XmlElement { static foo(string value) { enum opening = ""; enum closing = ""; return chain(opening, value, closing); } static bar(string value) { enum opening = ""; enum closing = ""; return chain(opening, value, closing); } } Note how two member functions are added to XmlElement and all of the 'opening' and 'closing' strings are computed at compile time. In my solution opDispatch() boils down to a "mixin template" itself. As Paul Backus's code does, that mixin template is used for adding the following members to the struct for each instantiation of opDispatch(). For example, for x, the struct will gain the following template definition. (_FOR_X is my annotation). mixin template opDispatch_FOR_X(alias code = codeImpl()) { private int _x; public auto x() { return _x; } public auto x(T val) { _x = val; return this; } } Note that each instance of opDispatch() for "x", "y", etc. will gain a template definition. Those definitions are a compile-time cost. Eventually, when user code mixes-in the corresponding template, then the three member above will be added to the user's struct. After that, there is no run-time cost more than adding those members by hand. Ali
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On 5/31/20 2:26 AM, Ali Çehreli wrote: Unfortunately, I could not reach the following cleaner syntax with a mixin template: mixin RW!int.x; Ok, I solved that too with a very convoluted "eponymous mixin template opDispatch." :) struct RW(T) { template opDispatch(string name) { static codeImpl() { import std.format; return format!q{ private %s _%s; public auto %s() { return _%s; } public auto %s(%s val) { _%s = val; return this; } }(T.stringof, name, name, name, name, T.stringof, name); } mixin template opDispatch(alias code = codeImpl()) { mixin (code); } } } struct Point { mixin RW!int.x;// <-- NICE :) mixin RW!int.y; // etc. } import std.traits; import std.stdio; void main() { pragma(msg, FieldNameTuple!(Point)); auto p = Point(1, 2); p.x = 42; p.y = 43; writeln(p); } Ali
Re: how to achieve C's Token Pasting (##) Operator to generate variable name in D?
On 5/30/20 11:28 PM, mw wrote: On Sunday, 31 May 2020 at 00:46:09 UTC, Paul Backus wrote: You can simplify this considerably using a mixin template [1]: --- mixin template RW(T, string name) { private T var; public T get() { return var; } public typeof(this) set(T val) { var = val; return this; } mixin("private alias _", name, " = var;"); // two aliases with the same name create an overload set mixin("public alias ", name, " = get;"); mixin("public alias ", name, " = set;"); } class Point { mixin RW!(int, "x"); mixin RW!(int, "y"); mixin RW!(string, "z"); // add } --- This is better, ... but it breaks std.traits: The following code solves that I think the following syntax is an improvement over Paul Backus's solution because it allows .x instead of "x" by taking advantage of a static opDispatch. But it requires parenthesis because now it's a string mixin, which is likely to be noticeably slow to compile too. struct RW(T) { static string opDispatch(string name)() { import std.format; return format!q{ private %s _%s; public auto %s() { return _%s; } public auto %s(%s val) { _%s = val; return this; } }(T.stringof, name, name, name, name, T.stringof, name); } } struct Point { mixin (RW!int.x); mixin (RW!int.y); // etc. } import std.traits; import std.stdio; void main() { pragma(msg, FieldNameTuple!(Point)); auto p = Point(1, 2); p.x = 42; p.y = 43; writeln(p); } The spec allows opDispatch to be an eponymous template: https://dlang.org/spec/operatoroverloading.html#dispatch Unfortunately, I could not reach the following cleaner syntax with a mixin template: mixin RW!int.x; Ali
Re: Overload function template for rectangular array
On 5/25/20 1:20 AM, John Chapman wrote: void foo(T)(T[] a) {} void foo(T)(T[][] a) {} auto ra = new int[][](5, 5); ra.foo(); // matches both import std.traits; void foo(T)(T[] a) if (!isArray!T) {} void foo(T)(T[] a) if (isArray!T) {} Or you can take T as parameter and check ElementType!T: import std.traits; import std.range; void foo(T)(T a) if (!isArray!(ElementType!T)) {} void foo(T)(T a) if (isArray!(ElementType!T)) {} void main() { auto ra = new int[][](5, 5); ra.foo(); } Ali
Re: alias this and initialisation
On 5/24/20 6:35 PM, Danni Coy wrote:> can anybody tell me why > > struct S > { > int x; > alias x this; > } > > void test() > { > S s; > s = 8; // this works > S s = 8 // but this does not? > } alias this is for implicit conversion, which requires an object to convert from. The second case above is about constructing an object. That's probably why it works that way. Ali
Re: How to flatten N-dimensional array?
On 5/24/20 2:37 AM, Pavel Shkadzko wrote: On Saturday, 23 May 2020 at 19:59:30 UTC, Ali Çehreli wrote: On 5/23/20 11:15 AM, Pavel Shkadzko wrote:> I have tried to implement a simple flatten function for multidimensional [...] Thank you, I was lacking practical examples for templates with "if" constructs, ehh. Template constraints are great but 'static if' can be more useful as it allows custom error messages: auto makeNdim(size_t N)(size_t length) { static if (N == 1) { auto result = iota(value, value + length).array; value += length; return result; } else static if (N > 1) { return iota(N).map!(n => makeNdim!(N - 1)(length)).array; } else { static assert(false, "N cannot be 0."); } } Ali
Re: Asserting that a base constructor is always called
On 5/23/20 3:04 PM, Tim wrote: I have a base class GameObject: /// Base class of most objects in the game class GameObject{ this(){ world[layer] = this; } abstract void update(){} void draw(){} } I want to make sure that whenever a class inherits from this, the base constructor is always called. Either that or have an assertion that gives an error if it isn't called. Thanks Is it not already called? I tried the following and it seems to work: import std.stdio; GameObject[1] world; enum layer = 0; /// Base class of most objects in the game class GameObject{ this(){ world[layer] = this; writeln("called"); } abstract void update(){} void draw(){} } class A : GameObject { this(int i) { writeln(__FUNCTION__); } override void update() { } } void main() { auto a = new A(42); } Ali
Re: How to flatten N-dimensional array?
On 5/23/20 11:15 AM, Pavel Shkadzko wrote:> I have tried to implement a simple flatten function for multidimensional > I'd like to clarify a couple of questions first. > > How come Phobos doesn't have "flatten" function for arrays? We call in 'joiner'. I wrote something like this: import std.stdio; import std.algorithm; import std.range; int value = 0; auto makeNdim(size_t N)(size_t length) if (N == 1) { auto result = iota(value, value + length).array; value += length; return result; } auto makeNdim(size_t N)(size_t length) if (N > 1) { return iota(N).map!(n => makeNdim!(N - 1)(length)).array; } auto flatten(R)(R range) if (!isInputRange!(ElementType!R)) { return range.joiner; } auto flatten(R)(R range) if (isInputRange!(ElementType!R)) { return range.map!(r => r.joiner).joiner; } void main() { auto a = makeNdim!3(5); writefln!"Original : %s"(a); writefln!"Flattened: %s"(a.flatten); } Output: Original : [[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]], [[10, 11, 12, 13, 14], [15, 16, 17, 18, 19]], [[20, 21, 22, 23, 24], [25, 26, 27, 28, 29]]] Flattened: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29] Ali
Re: None of the overloads of kill are callable using argument types:
On 5/18/20 1:11 PM, BoQsc wrote:> I'm trying to kill my own process, but I'm being unsuccessful at the > compilation of the program. It seems that neither getpid nor > thisProcessID returns a correct type value for the kill function. Of course, Adam D. Ruppe is right: You can simply return from main() in this case. Or, Pid is given to you for processes that you've spawned. Your question brings one of my recent pet peeves in software: the 'private' keyword.[1] In this case, it's Pid's constructor. I wanted to do the following but it failed because the constructor is private: auto p = new Pid(thisProcessID()); Ali [1] I don't think 'private' keyword ever protected me. I'm pretty sure of it because if I've ever reached for undocumented features of a type or if I've ever used any member, say, having a name starting with '_', I would be sure to be punished in the future if the implementation changed. I know that and I'm sure it's very easy to teach it to beginners. It's too much protecting me from myself. On the other hand, there have been multiple cases where 'private' keyword was hiding a useful feature: D runtime's GC statistics (at least in the past), some of std.getopt's parsing functions, etc. Note to self: Think twice before making anything 'private'.
Re: Type sniffing at runtime
On 5/15/20 11:12 PM, Alex wrote: static if(__traits(compiles, T.min)) writeln("Minimum value : ", T.min); A little improvement: static if(__traits(isFloating, T)) { writeln("Minimum value : ", -T.max); } else { writeln("Minimum value : ", T.min); } Ali
Re: Best way to refer to the type of a struct inside itself ?
On 5/15/20 8:04 AM, Paul Backus wrote: On Friday, 15 May 2020 at 14:55:07 UTC, Ali Çehreli wrote: Additionally, the name of a template when used inside that template means that instance of it. So just say Foo. :) struct Foo(A, B, C, size_t a, size_t b) { Foo * p; } Ali To expand a little, this works because a struct template such as the one above is actually syntax sugar for the following: template Foo(A, B, C, size_t a, size_t b) { struct Foo { // refers to the inner `struct Foo`, not the outer `template Foo` Foo* p; } } The relevant parts of the language spec are: - Aggregate Templates: https://dlang.org/spec/template.html#aggregate_templates - Eponymous Templates: https://dlang.org/spec/template.html#implicit_template_properties Yes, that is a consistent way of explaining it. :) As an off-topic trivia, the same feature is in C++ as well: #include template struct Foo { Foo * p; // <-- Foo means the template instance }; int main() { Foo f; f.p = } Ali
Re: Best way to refer to the type of a struct inside itself ?
On 5/15/20 7:37 AM, wjoe wrote: On Friday, 15 May 2020 at 13:52:38 UTC, Paul Backus wrote: On Friday, 15 May 2020 at 13:47:43 UTC, wjoe wrote: struct Foo(A, B, C, size_t a, size_t b) { alias foo_t = Foo!(A, B, C, a, b); // is there a better way to get foo_t ? } typeof(this) Thanks :) Additionally, the name of a template when used inside that template means that instance of it. So just say Foo. :) struct Foo(A, B, C, size_t a, size_t b) { Foo * p; } Ali