Re: How is opEquals used in toHash
On Tuesday, 18 May 2021 at 10:14:26 UTC, PinDPlugga wrote: But what I do not understand is why opEquals is necessary and where in the implementation of toHash it plays its role? Since area1 and area2 have different static arrays of Points I understand why `typeid(points).getHash()` would produce different values for each, but it seems like the opEquals should play a part in making them produce the same hash. opEquals plays no part in how toHash does its thing, but it's important for how AAs work. When there's a hash collision, the colliding items are placed in a bucket, which is generally iterated linearly to find the matching element, using opEquals. Example code: ```d struct S { int i; size_t toHash() const nothrow @safe { return 3; } bool opEquals(ref const S rhs) const { return i == rhs.i; } } unittest { int[S] a; a[S(1)] = 3; a[S(2)] = 4; // Hash collision - both return 3 assert(a.length == 2); // But they're both there assert(S(1) in a); assert(S(2) in a); int b = a[S(1)]; int c = a[S(2)]; assert(b == 3); assert(c == 4); } ``` And pseudocode for how an AA works: ```d struct AA(K, V) { import std.typecons : Tuple; alias Pair = Tuple!(K, "key", V, "value"); alias Bucket = Pair[]; Bucket[] buckets; this(int bucketCount) { buckets.length = bucketCount; } void opIndexAssign(V value, K key) { // Use hash to find correct bucket size_t hash = key.toHash(); size_t index = hash % buckets.length; Bucket bucket = buckets[index]; foreach (e; bucket) { if (e.key == key) { // Check for duplicates with opEquals e.value = value; // Overwrite existing return; } } bucket ~= Pair(key, value); // Array could reallocate when appended to, // so assign it back to the bucket list buckets[index] = bucket; } V opIndex(K key) { // Use hash to find correct bucket size_t hash = key.toHash(); size_t index = hash % buckets.length; Bucket bucket = buckets[index]; foreach (e; bucket) { if (e.key == key) { // Check with opEquals return e.value; } } throw new Exception("Key not found"); } } unittest { AA!(S, int) a = AA!(S, int)(24); a[S(1)] = 3; a[S(2)] = 4; assert(a[S(1)] == 3); assert(a[S(2)] == 4); } ``` This omits plenty of details, but should give some idea how AAs work. -- Simen
Re: type of functions
On Monday, 10 May 2021 at 10:37:51 UTC, Alain De Vos wrote: Can I say that the compiler is intelligent enough to add the attributes "pure nothrow @nogc @safe" ? Yes, in those cases (and some others). The functionality is described here: https://dlang.org/spec/function.html#function-attribute-inference -- Simen
Re: Dlang equivalent of #define/#ifdef : not... version
On Tuesday, 20 April 2021 at 18:57:46 UTC, ichneumwn wrote: So my questions: - is there a module-crossing equivalent of "version"? mw covered this. There's more documentation here: https://dlang.org/spec/version.html#version https://dlang.org/dmd-windows.html#switch-version - if not, is there some way I could test for the existence of the enum can_i_test_for_this? A SymbolExists!() or ModuleHasSymbol!() or ModuleHasMember!() ? __traits(hasMember, features, "i_am_not_a_feature") This is actually what std.traits.hasMember does, but for some reason it can't take a module as its first argument. -- Simen
Re: How can I allocate a int[] array on stack?
On Friday, 26 March 2021 at 14:27:58 UTC, Jack wrote: On Friday, 26 March 2021 at 06:45:39 UTC, Daniel Kozak wrote: On Fri, Mar 26, 2021 at 7:36 AM Daniel Kozak wrote: On Fri, Mar 26, 2021 at 7:31 AM Daniel Kozak wrote: On Fri, Mar 26, 2021 at 6:50 AM Jack via Digitalmars-d-learn < digitalmars-d-learn@puremagic.com> wrote: What's the equivalent of C's VLA in D? scoped from std.typecons doesn't seem to work with arrays. Should I use alloca() for my array or is there something else? https://dlang.org/library/std/array/static_array.html Sorry I was misread this You can use allocator: import std.experimental.allocator.showcase; import std.experimental.allocator; import std.stdio; StackFront!4096 stackAlloc; void main() { int[] a = stackAlloc.makeArray!int(2); writeln(a); } I thought this was going to use alloca() but it seems to be using malloc() internally? Basically, StackFront is an allocator that allows any size allocation, but prefers to put things in its memory block on the stack. If there's no space left on the stack, it puts things on the heap. Not quite what you're asking for, in other words. StackFront is basically this: struct StackFront(size_t size) { ubyte[size] memory; size_t used; T allocate(T)() { if (used + T.sizeof > size) return *cast(T*)malloc(T.sizeof); auto result = *cast(T*)[used]; used += T.sizeof; return result; } } With more bells and whistles, but it's a fixed-size block of memory on the stack that falls back to heap allocation when there's no more room in the block. alloca is probably your best bet if you need dynamic-size stack allocation. That said, it's a "you're on your own" kind of solution. Use it if you know it's the best solution for your problem. -- Simen
Re: Opaque type (struct) with a static immutable fails to compile without constructor - why?
On Thursday, 4 March 2021 at 13:58:48 UTC, frankp wrote: Hi all, I want to make an opaque type that simply contains an integer with some immutable constants and toString pretty printing. Like this: struct Foo_t { private long foo; alias foo this; static immutable long Inf = long.max; //1) void toString(...){} } On dmd 2.092.1 this fails with: 1) Error: cannot implicitly convert expression 9223...L of type immutable(long) to Foo_t I simply want to initialize an immutable long with long.max. Why the conversion to Foo_t ? If I add a constructor: private this(long f) { foo = f; } It compiles but according to code coverage this constructor is never called. What's going on? I tried compiling your code locally on DMD 2.094.1, and had no issues. Again with 2.095.0, no issues. On run.dlang.io, with all dmd compilers from 2.060, and it just plain works. Now, that's after removing ... from toString. With that present, it fails with some variation of 'Error: undefined identifier '__va_list_tag''. Most likely, you have shortened your program for clarity, and removed the issue you're experiencing in the process. Can we have another one, with the issue still there? -- Simen
Re: Templated delegate as template argument for structs
On Saturday, 20 February 2021 at 09:16:46 UTC, Simon van Bernem wrote: I have the following struct declaration: struct Hash_Table(Key, Value, u32 delegate(ref Key) custom_hash_function = null) [snip] I take it from the error that the problem is not actually the delegate that I am passing, but the fact that the delegate type has another template parameter as the argument type. Can template arguments in D not reference previous template arguments? Is there some way I can get around this? The D way would be an alias parameter: struct Hash_Table(Key, Value, alias custom_hash_function) { // ... } Probably also adding a constraint: struct Hash_Table(Key, Value, alias custom_hash_function) if (is_valid_hash_function!(Key, custom_hash_function)) { // ... } // Check if the hash function can be called with a Key // as argument, and the result be assigned to a u32 enum is_valid_hash_function(Key, alias fn) = __traits(compiles, (Key k){ u32 u = fn(k); }); D lets you refer to other template parameters in the same template parameter list in three cases, as far as I know: 1) A type may be a subtype of an earlier parameter: class C {} struct S(TBase, TDerived : TBase) {} S!(Object, C) a; 2) A type parameter with a type specialization followed by template parameter list: struct Fn(U) {} struct S(T: Fn!Arg, Arg) {} S!(Fn!int) a; 3) Following a type parameter, a value parameter of that type may appear: struct S(T, T value) {} S!(int, 4) a; The first two can also be combined: struct Fn(U) {} struct S(T1, T2: Fn!T3, T3 : T1) {} S!(int, Fn!int) a; However, it seems 3) only works with that specific type, modulo storage classes. No Foo!T, no void delegate(T). At any rate, the alias parameter is the way it's generally done, and is more flexible, so just leave it at that. -- Simen
Re: Creating 1000 instances
On Friday, 19 February 2021 at 10:02:05 UTC, Siemargl wrote: On Friday, 19 February 2021 at 08:29:36 UTC, Ferhat Kurtulmuş wrote: Since classes are reference types all instances of files will be the same reference of "new File()", which you probably don't want. Is any differences between x and y definitions? MyClass [] x, y; x = new MyClass[7]; y= new MyClass[](8); The only part of the documentation I've found that talks about this is here: https://dlang.org/spec/expression.html#new_expressions The main difference I know of comes with multidimensional arrays: auto a = new int[4][4]; pragma(msg, typeof(a)); // Prints int[4][] auto b = new int[][](4,4); pragma(msg, typeof(b)); // Prints int[][] Since the former is a dynamic array of static arrays, the first size parameter cannot be passed at runtime: auto n = 4; // Error: variable n cannot be read at compile time auto c = new int[n][n]; But must be a compiletime constant: enum N = 4; auto d = new int[N][n]; pragma(msg, typeof(d)); // Prints int[4][] The other syntax however, can take runtime values, but does not encode the size in the type: auto e = new int[][](n,n); pragma(msg, typeof(e)); // Prints int[][] The other big thing about the []() syntax is it actually initializes the arrays of arrays for you: assert(e[0].length == n); If you were to use new int[][n], you would need to initialize each array of arrays manually: auto f = new int[][n]; assert(f[0].length == 0); // it's empty foreach (i; 0..n) { f[i] = new int[n]; // Have to do this yourself. } -- Simen
Re: Two "references" to dynamic array, why not change both when reallocating?
On Wednesday, 11 November 2020 at 10:17:09 UTC, zack wrote: I am new to D. Appending to an array can lead to reallocation, that's clear. But why is the "reference" b not changed accordingly to the new position and still points to "old" memory? Why is b not also changed when reallocating array a and the old data getting invalid/freed? auto a = [55,10,20]; auto b = a; a ~= [99,99,99,99,99,99]; a[0] = 1; assert(b[0] == 1); // could fail (similar to p.103-104 in "The D Programming language") The short answer is 'because that's how we've chosen to define it'. A more involved answer is that changing every reference is prohibitively expensive - it would require the equivalent of a GC collection on every reallocation, as references to the array could exist anywhere in the program, be that on the stack, heap, even on other threads. That's the performance side of it. Another heavy argument is 'can you make it behave the other way?' Currently, that's simple: use a pointer to a slice (T[]*), and share that around. I don't see how I would get the current behavior if reallocation caused reassignment of all references (though admittedly I haven't thought too much about it). Next up: does b, ending on the same element as a, refer to the whole length of a (i.e. should b's length be reassigned when a is reallocated?), or is it a slice only referencing the first three elements? Either choice is going to be unexpected in some cases. All in all, there's many reasons to choose the behavior D has chosen. There are some drawbacks, but I feel it's the right choice. -- Simen
Re: How add class or struct member after construction?
On Thursday, 5 November 2020 at 22:48:38 UTC, Marcone wrote: How add class or struct member after construction? Is it possible in D? How? This depends a lot on what you mean. The short answer is no - you cannot. However, given some limitations, it is possible. What sort of members do you need to add, and how will you be using them? For instance, this works: struct S { import std.variant; Variant[string] members; Variant opDispatch(string name)() { return members[name]; } Variant opDispatch(string name, T)(T value) { return members[name] = value; } } unittest { S s; s.foo = 13; assert(s.foo == 13); } -- Simen
Re: this T / variadic template and interfaces
On Monday, 26 October 2020 at 11:14:47 UTC, frame wrote: Did not find this topic: I have an interface and some wrapper classes that use it. The wrapper's methods should accept variadic arguments. The runtime should only work with the interface, trying casting to a wrapper is not an option, because it's a plugin design. - defining a variadic template in wrapper does not work, because we are working with the interface only and compiler complains method is not callable with argument X - defining a variadic template without body in interface causes linker errors, which makes sense somehow - defining a variadic template with body in interface could work if the compiler would get the right "this" type but sadly, "this" refers to interface and also "this T" refers to interface too. Is there any way to get this working? I know, I could use a known object to feed the arguments and use that instead - but I want to keep things simple as possible. Templates can't be virtual, so even if they can be defined in an interface, you can't override them in a class that implements said interface - the implementation needs to be in the interface itself. This makes sense if you consider that the user of the interface has no knowledge of the types that implement it, and vice versa: the implementing class has no idea which instantiations to make, and the user has no idea which implementing classes to create instantiations for. Templates require that the user have full knowledge of the templates to be instantiated. There are some workarounds of sorts, but they depend heavily on what you're trying to achieve. Can you use an array of std.variant.Variant, for instance? -- Simen
Re: Call method of object variable
On Friday, 16 October 2020 at 08:12:59 UTC, Andrey wrote: Hi, I have got: struct Qaz { wstring read() {return null;} wstring hear() {return "";} } void main() { // ... static if(some_condition) alias method = Qaz.hear; else alias method = Qaz.read; // ... Qaz qaz; qaz.method(); // ??? } How to call alias "method" on object "qaz"? https://dlang.org/spec/traits.html#child The resulting code would be: __traits(child, qaz, method)(/*arguments go here*/); -- Simen
Re: Why is "delete" unsafe?
On Wednesday, 23 September 2020 at 04:15:51 UTC, mw wrote: It's there because there _are_ times when it makes sense and is useful, but it's definitely not safe, so you have to be careful and know what you're doing. What do you mean by saying "it's definitely not safe" here? I mean: if I'm careful and know what I'm doing, e.g. remove all the reference to any part of the `object` before call core.memory.GC.free(object), is there still any inherit "unsafe" side of `free` I should be aware of? FYI: I just described my use case here: https://forum.dlang.org/post/hzryuifoixwwywwif...@forum.dlang.org If there are no lingering references, the function calling free() can safely be made @trusted. -- Simen
Re: Why private methods cant be virtual?
On Tuesday, 22 September 2020 at 13:19:10 UTC, Daniel Kozak wrote: So final private functions can be overriden? It seems not, but the sentence is definitely confusing if not just plain wrong. Yeah. I've seen this called hiding, shadowing and overwriting earlier, but never overriding - that's always been reserved for the polymorphic kind. I'd argue the documentation should use one of those other terms. And yes compiler probably could findout that method could be made non-virtual but I am not sure how easy is this and how it would slow down compilation times Steve showed a few posts up one example that would make it basically impossible. Other language features make it even worse: class A { private void fun() {} } class B(string s) : A { mixin(s); } -- Simen
Re: Why is dtor called for lazy parameter?
On Friday, 18 September 2020 at 14:14:31 UTC, Andrey Zherikov wrote: It seems that dtor is called at exit from lazy delegate, not at exit form create(): == create() .do_something() .do_lazy() .do_something(); == Output: == -> void test.main() -> test.do_lazy(lazy S s) -> test.create() 1 S test.S.this(int n) <- test.create() -> 1 test.do_something(S s) <- 1 test.do_something(S s) 1 void test.S.~this() ===-1 <- test.do_lazy(lazy S s) -> 1703096 test.do_something(S s) <- 1703096 test.do_something(S s) <- void test.main() == This doesn't even allow me to copy the value of 's' in do_lazy(). You're right, I missed a step: do_lazy() takes a S, not a scoped!S, so the conversion from scoped!S to S happens after create() has returned and before the value is used in do_lazy. This explains my confusion earlier. D's lazy is essentially the same as a delegate or function, so you could* rewrite to this (writelns omitted for clarity): S do_lazy(S function() s) { return s(); } void main() { (() => cast(S)create()) // Here .do_lazy() .do_something(); } On the marked line, the cast from scoped!S to S happens, the scoped!S goes out of scope and the destructor is called. *There may be differences, but for this discussion these are not important. -- Simen
Re: Why is dtor called for lazy parameter?
On Friday, 18 September 2020 at 12:32:49 UTC, Andrey Zherikov wrote: == The output is: == -> void test.main() -> test.do_lazy(lazy S s) -> test.create() 1 S test.S.this(int n) <- test.create() 1 void test.S.~this() ===-1 (2) <- test.do_lazy(lazy S s) -> 1703096 test.do_something(S s) <- 1703096 test.do_something(S s) <- void test.main() == As you can see, dtor is called before writeln on (1) and s1.i is -1 (2) Indeed. As we can see from the output, first do_lazy() is called from test.main, then create() is called (this happens inside do_lazy, as s is lazy). When create() returns, the scoped!S you created goes out of scope and is destroyed. scoped's destructor overwrites the memory with S.init, which is why s.i is -1 at that point. Then the memory is overwritten by subsequent function calls, as that stack space is now considered vacant. That's why the output changes from -1 to 1703096. A bit interesting is the fact that <- test.create() is printed before ~this(). I expected the order to be opposite, but there may be sensible reasons why it's not. scoped!S is only valid inside the scope its variable exists in, and when that scope is exited, it refers to random stack data. It's a lot like this code: int* fun() { int a; int* p = return p; } Note that return does not compile, with a warning about escaping a reference to a local variable. That's exactly the same thing that's happening with scoped!S, but since scoped is more complex, the compiler has a hard time keeping track of things, and code that in a perfect world would not compile, does. It may be that D's scope tracking functionality has become good enough to catch this error now, if the functions are properly marked. Even if this is the case, then they are obviously not properly marked. :p Now, this begets the question: *when* should I use scoped!T? Short answer: Basically never. Longer answer: 1) When the lifetime of one object needs to be a strict subset of another. That is, the class instance you created only exists as long as the function create() is on the stack. When scoped!T is a member of another class or struct, it continues to live as long as that object exists. In most cases, you don't mind that it stays around for longer, and can let the GC handle the cleanup. If you really do care, you can use scoped!T, or explicitly destroy the object when you're done with it. 2) scoped!T may be used as a performance hack, letting you avoid the GC. If you have instrumented your code and found that this is the culprit, scoped!T might help. Even if GC is the problem, you'll still need #1 to be true. There may be other cases, but I believe those are the main two reasons to use scoped!T. -- Simen
Re: Why is dtor called for lazy parameter?
On Friday, 18 September 2020 at 10:43:47 UTC, Andrey Zherikov wrote: Why is dtor called before returning from do_lazy function - see (1)? It seems cause uninitialized parameter in do_something call after it in (2)-(3). As ikod mentions, it's because of scoped!S. As for why it does this, yeah, this is kinda egregious. The documentation[0] of scoped mentions this issue: This facility is unsafe; it is the responsibility of the user to not escape a reference to the object outside the scope. As the name implies, scoped!T limits the valid scope of a reference to the scope of the variable holding it. You're putting it on the stack, so the moment the variable goes off the stack (when do_lazy returns), the reference is destructed. -- Simen [0]: https://dlang.org/library/std/typecons/scoped.html
Re: Type inference for constructors
On Friday, 18 September 2020 at 05:43:56 UTC, data pulverizer wrote: I’d like to know if constructors of classes and structs can have type inference. So far, I am using a separate function for this purpose, for example: ``` import std.stdio: writeln; struct Pair(T, U) { T first; U second; this(T first, U second) { this.first = first; this.second = second; } } Pair!(T, U) pair(T, U)(T first, U second) { return Pair!(T, U)(first, second); } void main() { auto mp = pair("Michael", 32);//standard function inference works //auto m0 = Pair("Michael", 32); //I’d like to be able to do this writeln("pair: ", mp); } ``` That's issue 1997: https://issues.dlang.org/show_bug.cgi?id=1997 D's templates are turing complete, and there may be arbitrary amounts of logic obscuring the mapping between type template parameters and the specific argument types of the type's constructor, so the problem is intractable in the general case. E.g: template Foo(T) { static if (is(T == int)) { struct Foo { this(int i) {} // int-specific code } } else { struct Foo { this(T t) {} // generic code } } } The above example is a simple one, yet mapping from a constructor call to the correct template parameters is difficult. [I] wondered what `this` in the code below does: ``` auto ref opIndex(this X, D...)(auto ref D i) { return a[i]; } ``` That's a template this parameter (https://dlang.org/spec/template.html#template_this_parameter). It takes on the type of 'this' at the point of instantiation. That is: struct S { void fun(this T)() { pragma(msg, T); } } unittest { S s; const S sc; immutable S si; shared S ss; s.fun(); // prints S sc.fun(); // prints const(S) si.fun(); // prints immutable(S) ss.fun(); // prints shared(S) } This allows the return type to have the same constness as 'this', or for specific code to be executed when operating on e.g. a non-mutable instance, where lazy initialization couldn't be performed. In many cases, this is better served by using inout: https://dlang.org/spec/function.html#inout-functions -- Simen
Re: another question on hidden mixin names
On Thursday, 17 September 2020 at 21:05:59 UTC, 60rntogo wrote: struct V { int x; mixin assign!"+"; // mixin assign!"-"; } However, if I uncomment the second mixin, there is an error "v is not a scalar, it is a V". I guess I somehow need to merge these overloads, but I don't know how. Usually, that would be: struct V { int x; mixin assign!"+" a; mixin assign!"-" b; alias opOpAssign = a.opOpAssign; alias opOpAssign = b.opOpAssign; } However, I can't seem to get that working. It seems to be an instance of this issue: https://issues.dlang.org/show_bug.cgi?id=18118 Note that explicitly calling the methods does work: v.opOpAssign!"-"(v); v.opOpAssign!"+"(v); I don't know any good workarounds for this, you'll probably have to write a separate opOpAssign method for V that performs the forwarding to the mixed-in methods. This is, to put it very nicely, not an optimal solution. btw, I'm somewhat surprised by your use of a template this parameter (https://dlang.org/spec/template.html#template_this_parameter). Generally this will work, but you're probably better off with ref auto opOpAssign(string op)(typeof(this) rhs) if (op == op_) -- Simen
Re: enum and const or immutable ‘variable’ whose value is known at compile time
On Thursday, 17 September 2020 at 10:56:28 UTC, Mike Parker wrote: On Thursday, 17 September 2020 at 09:44:20 UTC, claptrap wrote: Seriously how it's implemented is irrelevant. And to be clear, my point wasn't about how it's implemented. My point was that: enum { foo = 10; } and enum foo = 10; Are effectively the same thing, whether it's implemented that way or not. So why on earth would a new keyword be necessary? I could imagine some new users may think in enum foo = someTemplate!(); someTemplate could evaluate to a list of values like a 'normal' enum. That's just conjecture, though. The one thing I dislike about enum like this is that we have another keyword that's able to handle manifest constants when tickled correctly, and which doesn't evoke the image of an enumerated list of values: import std.meta : Alias; alias foo = Alias!([1,2,3]); alias bar = Alias!9; alias baz = Alias!someFunc; Some of the above may be doable without Alias!(), but not all. I don't know if you remember the discussions when bracketless enums were introduced back in 2007ish, but alias was the prime contender back then, and is slowly gaining the power that was requested at the time (the ability to alias values as above was added fairly recently). To quote Bill Baxter from way back when (https://forum.dlang.org/post/fjdc4c$2gft$1...@digitalmars.com): > Why does: > final int x = 3; > make any more intuitive sense than: > enum int x = 3; > ? There are these things called "words". And they have "meanings"... enum: (short for "enumeration", the noun form of "enumerate") "to specify one after another : list" final: "not to be altered or undone " To be clear: I don't mind 'enum' being used this way, but if I were to do things over again, I would have used 'alias'. -- Simen
Re: Neater "not version (...)" ?
On Wednesday, 16 September 2020 at 19:04:24 UTC, Vladimirs Nordholm wrote: On Wednesday, 16 September 2020 at 18:54:45 UTC, Jacob Carlborg wrote: version (Windows) enum windows = true; else enum windows = false; static if (!windows) { // ... my code } Ah, I guess it boils down to this then. Doesn't really make it "neater", but thank you for the tip! I wrote this helper a little while back: struct Version { template opDispatch(string name) { mixin("version ("~name~") enum opDispatch = true; else enum opDispatch = false;"); } } static if (Version.Windows) pragma(msg, "Windows machine"); static if (Version.linux) pragma(msg, "Linux machine"); Note that it only works for global versions, and those defined in the same module as Version. -- Simen
Re: Why does compose from std.functional return a templated function
On Wednesday, 16 September 2020 at 09:59:59 UTC, Jan Hönig wrote: I have toyed with the compose template in std.functional and ran into some problems. rikki_cattermole on discord helped me a lot to solve my problem. However, what still remains (for me) to understand is why. Source code for `compose`: https://github.com/dlang/phobos/blob/master/std/functional.d#L1161 `compose` pipes together given functions. And returns a TEMPLATED function. Why does it return a templated function? At compile-time, compose definitly knows, what kinds of function it composes together. So with std.traits, it could put there a definitve type, depending on the given function(s). I somewhat see, that inside compose itself, this probably solves some issues with casting (maybe). However, the last composition, i.e. the one which is returned, does not need to be templated, since it is known, what parameter has the last function. In my case, I failed to understand, that it returns a non-initialized template function, which lead into compile problems. In general I can imagine that this leads to weird compile errors, which are hard to understand. (types, casting, etc.) My main question is why? Is there something, which I am missing, that explains, why it is beneficial to return a templated function? (maybe, because I might want to compose together templated non-initialized functions?) It's perfectly possible to compose templated functions without wanting to specify the template parameters, and not allowing this would significantly hamper compose's usability. The other complication is overloads. Here's a version of compose that generates the correct overloads: template getOverloads(alias fn) { static if (__traits(compiles, __traits(getOverloads, __traits(parent, fn), __traits(identifier, fn), true))) { alias getOverloads = __traits(getOverloads, __traits(parent, fn), __traits(identifier, fn), true); } else { alias getOverloads = fn; } } template compose(funs...) if (funs.length > 0) { static foreach (overload; getOverloads!(funs[$-1])) { static if (__traits(isTemplate, overload)) { auto compose(Args...)(Args args) { static if (funs.length == 1) { return overload(args); } else { return funs[0](.compose!(funs[1..$])(args)); } } } else { import std.traits : Parameters; auto compose(Parameters!overload args) { static if (funs.length == 1) { return overload(args); } else { return funs[0](.compose!(funs[1..$])(args)); } } } } } As you can see, this is *a lot* more complex than the version in std.functional. The benefit is you can take the address of it easily. Here's how you can do the same with std.functional.compose: import std.functional : compose; import std.meta : Instantiate; unittest { auto sun = !(compose!(fun, gun), int); sun(3); } void fun(T)(T t) { } int gun(int t) { return t; } I will argue the latter is an acceptable cost of avoiding the dense, bug-prone monstrosity of the former. -- Simen
Re: Get enum value name as string at compile time?
On Monday, 14 September 2020 at 03:48:51 UTC, Steven Schveighoffer wrote: Consider the enum: enum Foo { a, b } Foo.a.stringof => "a" enum x = Foo.a; x.stringof => "cast(Foo)0" Is there another way I can take an enum value that's known at compile time (but not the actual identifier), and get the name of it? I know I can use a switch, or to!string. But I was hoping this was easy for the compiler to figure out some way without involving CTFE. It is a bit weird that x.stringof doesn't simply return the name like Foo.a.stringof does. Anyways, this works: template enumName(alias a) { import std.meta : staticIndexOf, staticMap; alias T = typeof(a); enum getValue(string name) = __traits(getMember, T, name); alias enumValues = staticMap!(getValue, __traits(allMembers, T)); enum enumName = __traits(allMembers, T)[staticIndexOf!(a, enumValues)]; } enum Foo { a = 2, b = 19 } enum x = Foo.a; pragma(msg, enumName!x); // "a" -- Simen
Re: sending the address of a struct
On Sunday, 6 September 2020 at 09:58:54 UTC, Johann Lermer wrote: pointer. The error message says: std.concurrency.MessageMismatch@std/concurrency.d(237): Unexpected message type: expected 'shared(Env*)', got 'shared(test.Env)*' The error message gives you all the information you need - notice the position of the asterisk inside the parens on one, outside on the other? The pointer itself is not shared, only the pointee - the data pointed to. This works: auto e = receiveOnly!(shared(Env)*); -- Simen
Re: tupleof seems to break encapsulation
On Friday, 4 September 2020 at 10:16:47 UTC, 60rntogo wrote: Consider the following code. foo.d --- module foo; struct Foo { private int i; } --- main.d --- void main() { import std.stdio; import foo; auto x = Foo(); writeln(x); // ++x.i; ++x.tupleof[0]; writeln(x); } --- As expected, the commented line does not compile. If I uncomment it, I get the error "no property i for type foo.Foo". However, the rest of the code compiles just fine and outputs: --- Foo(0) Foo(1) --- This appears to defeat the purpose of declaring i private. What am I missing? It's a known issue: https://issues.dlang.org/show_bug.cgi?id=19326 There are some very good reasons to allow some access to private fields, though it should be more limited than is currently the case. -- Simen
Re: Tuple poilerplate code
On Tuesday, 1 September 2020 at 02:08:54 UTC, JG wrote: Is there anyway to remove the boilerplate code of dealing with tuples: I find myself having to write things like this fairly often auto someRandomName = f(...); //where f returns a tuple with two parts auto firstPart = someRandomName[0]; auto secondPart = someRandomName[1]; Is to possible to write something so that the above is essentially equivalent to: assignTuple!(firstPart,secondPart) = f(...); The closest I can produce is using a template mixin so that I would have to write: mixin AssignTuple!(()=>f(...),"firstPart","secondPart"); When you know the types, this works: import std.typecons : tuple; import std.meta : AliasSeq; int firstPart; string secondPart; AliasSeq!(firstPart, secondPart) = tuple(1, "foo"); assert(firstPart == 1); assert(secondPart == "foo"); I know Timon Gehr worked on a DIP for improved tuples, which I think would include the syntax `auto (firstPart, secondPart) = tuple(1, "foo");`, but I don't know what's happened to that idea lately. I also feel it's worth pointing out that Paul Backus' code looks elegant when used outside a map as well: tuple(1, "foo").unpack!((i, s) { writeln("i (", typeof(i).stringof, "): ", i, ", s (", typeof(s).stringof, "): ", s); }); Will print: i (int): 1, s (string): foo -- Simen
Re: Wrong selection of opEquals for objects.
On Friday, 28 August 2020 at 13:35:43 UTC, Alexandru Ermicioi wrote: On Friday, 28 August 2020 at 12:29:20 UTC, Simen Kjærås wrote: Seems that these methods should be rooted out from Object, and placed in respective interfaces like: - interface Equatable(T) { bool opEquals(T value); } - Then it would be a lot more simple. People who want equality check, will implement interface with right type, for example Equatable!Object. Yup, it's been proposed, but nothing's come of it yet. Here's Andrei's DIP on ProtoObject, which apparently is untouched for over two years now: https://github.com/andralex/DIPs/blob/ProtoObject/DIPs/DIP.md The main problem with solving this issue is doing so will break all code that uses the current system. This is clearly suboptimal. -- Simen
Re: Wrong selection of opEquals for objects.
On Friday, 28 August 2020 at 10:42:09 UTC, Alexandru Ermicioi wrote: No that is not a solution at all, in template code that requires safety. You basically will have to sacrifice safety for rest of types, such as structs, unions & enums for the sake of objects being able to compare. Yup. There's a reason I'm saying it's suboptimal. FWIW, you can limit the taint by using @trusted lambdas. One of the reasons this hasn't been fixed is idiomatic D code very rarely uses classes, but that does not mean they're always the wrong tool. Could we just template that opEquals in this manner: --- bool opEquals(T : Object, X : Object)(T lhs, X rhs) { if (lhs is rhs) return true; if (lhs is null || rhs is null) return false; if (!lhs.opEquals(rhs)) return false; if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) { return true; } return rhs.opEquals(lhs); } --- That would at least allow us to define an overload which is safe and would be picked up by new implementation. I'm wondering why it wasn't done yet, are there any reasons for that? The template solution may look like it solves every problem, but it really doesn't. Consider this code: class A { bool opEquals(A) { return false; } } class B : A { bool opEquals(B) { return true; } } unittest { B b1 = new B(); B b2 = new B(); A a1 = b1; A a2 = b2; assert(b1 == b2); assert(a1 != a2); // WTF? } With the template solution, the function in B would be ignored when stored in a variable with static type A. This solution would sometimes do the right thing, other times it would silently do the wrong thing. Also, why it is limited to just objects? It seems that this function enforces symmetry between two objects. What about rest of the possible types, such as structs, unions? That's an issue. The spec clearly states (https://dlang.org/spec/operatoroverloading.html#equals): 2. [T]he expressions a.opEquals(b) and b.opEquals(a) are tried. If both resolve to the same opEquals function, then the expression is rewritten to be a.opEquals(b). 3. If one is a better match than the other, or one compiles and the other does not, the first is selected. 4. Otherwise, an error results. This is clearly not the case: struct S1 { bool opEquals(S2 a) { return true; } } struct S2 { bool opEquals(S1 a) { return false; } } unittest { S1 a; S2 b; assert((a == b) == (b == a)); // Fails } I didn't find a bugzilla entry on this, but I'm pretty sure there is one. As for why there's no global function like for classes, that's because there's no need - there is no disconnect between the static and dynamic types of non-class variables (or, if there is, it's explicitly programmed in, like in std.variant.Variant). -- Simen
Re: Wrong selection of opEquals for objects.
On Friday, 28 August 2020 at 08:16:01 UTC, Alexandru Ermicioi wrote: Hi everyone, there is https://issues.dlang.org/show_bug.cgi?id=21180 bug, anyone knows how to avoid it? Test case: - import std; class Silly { bool opEquals(const Silly silly) const @safe { return silly is this; } alias opEquals = Object.opEquals; } bool comp(T)() @safe { return new T() == new T(); } void main() { comp!Silly.writeln; comp!(const Silly).writeln; comp!(immutable Silly).writeln; } - It always tries to call Object.opEquals, when narrower overload should've been selected. - Alex. Essentially, this boils down to the issues described in https://issues.dlang.org/show_bug.cgi?id=1824, and a host of other bugzilla issues. When you do a == b with a and b being class objects, it's lowered to object.opEquals(a, b)[0], which casts both a and b to Object before doing the comparison. So, you'll need to override Object.opEquals to have the right function called: class Silly { int field; this(int f) { field = f; } override bool opEquals(Object o) { auto silly = cast(Silly)o; // If cast returns null, it's not a Silly instance if (!silly) return false; // Compare Silly objects return field == silly.field; } } unittest { Silly a = new Silly(1); assert(a == new Silly(1)); assert(a != new Silly(2)); } That takes care of choosing the correct overload, but as you may have noticed, there's another issue: your @safe function comp() can't call the @system function object.opEquals. Since object.opEquals operates on Object instances, not your specific subclass, it has to assume the worst, and is @system. There's no real good solution to that in the language as of now, and some of us have been pulling our hair for years because of it. What you'll need to do is mark every function that does compare two class objects with == as @trusted or @system. -- Simen [0]: https://github.com/dlang/druntime/blob/master/src/object.d#L166
Re: Can a call to pragma(msg, __FILE__, ...) be mixin templatized?
On Tuesday, 18 August 2020 at 08:05:20 UTC, Per Nordlöw wrote: On Tuesday, 18 August 2020 at 08:03:04 UTC, Per Nordlöw wrote: Forgot to mention that I want to support variadic arguments to `ctLog` similar to what is done with And these arguments should be of any template argument kind, not only a compile-time string. I'm not a fan of string mixins (ask Adam how they're the scourge of good programming, a wart on D's behind, and so on :p), but I found no good way to do this without them: string ctLog(Args...)(string file = __FILE__, size_t line = __LINE__) { import std.conv : to; string result = `pragma(msg, "`~file~`(", `~line.to!string~`, "): "`; static foreach (e; Args) { result ~= `, `~e.stringof; } return result~`);`; } mixin(ctLog!("This ", "is ", "module ", "scope.")); unittest { mixin(ctLog!"function scope"); } struct S { mixin(ctLog!"Struct scope"); } -- Simen
Re: Can a call to pragma(msg, __FILE__, ...) be mixin templatized?
On Monday, 17 August 2020 at 21:18:41 UTC, Per Nordlöw wrote: I'm using pragma(msg, __FILE__, "(", __LINE__, ",1): Debug: ", "A useful debug message"); to print compile-time information formatted as standard compiler diagnostics. These are picked up by Emacs Flycheck and overlayed in the editor and listen in the *Flycheck errors* buffer. Very convenient. When I want to get the type of something at compile-time. In order to not having to repeat oneself I'm now looking for a way to extract this into a `mixin template`. Is this possible somehow and still preserve the instantiation site values of `__FILE__` and `__LINE__`? mixin template ctLog(string msg, string file = __FILE__, size_t line = __LINE__) { pragma(msg, file, "(", line, "): ", msg); } mixin ctLog!"Module scope"; unittest { mixin ctLog!"function scope"; } struct S { mixin ctLog!"Struct scope"; } This works for me. -- Simen
Re: Template: get function name
On Monday, 17 August 2020 at 08:07:32 UTC, novice3 wrote: Hello. I have wrapping Windows API functions, wich return 0 on success and erroro code on failure. I copy wenforce template as: ``` private T denforce(T, S)(T value, lazy S msg = null, string file = __FILE__, size_t line = __LINE__) { import core.sys.windows.winerror: NO_ERROR; import std.conv: to; if (value != NO_ERROR) throw new WindowsException(value, to!string(msg), file, line); return value; } ``` and use it: ``` DhcpEnumServers(0, null, servers, null, null).denforce("DhcpEnumServers"); Then windows api - extern (Windows)DhcpEnumServers - return error, then Windows exception throwed with name of failed api "DhcpEnumServers". Can we change template to avoid api name dublicate? Can denforce template obtain "DhcpEnumServers" function name to format message "DhcpEnumServers api failed"? Thanks. Take the function as an alias parameter and wrap the entire call: auto denforce(alias fn, string file = __FILE__, size_t line = __LINE__, Args...)(Args args) { import core.sys.windows.winerror: NO_ERROR; auto value = fn(args); if (value != NO_ERROR) { throw new WindowsException(value, __traits(identifier, fn)~" api call failed.", file, line); } return value; } unittest { denforce!DhcpEnumServers(0, null, servers, null, null); } For bonus points, you could also get the error message for the returned error code: string convertErrorCode(uint code) { import core.sys.windows.winbase : FormatMessage, LoadLibrary, FORMAT_MESSAGE_FROM_SYSTEM, FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_FROM_HMODULE; wchar[512] buf; auto written = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, code, 0, buf.ptr, buf.length, null); if (!written) { auto inst = LoadLibrary("Ntdsbmsg.dll"); if (inst) { written = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, inst, code, 0, buf.ptr, buf.length, null); } } if (written) { import std.conv : to; return buf.ptr.to!string; } else { import std.format : format; return format("An unknown error occured: %x", code); } } unittest { import core.sys.windows.winerror : ERROR_INVALID_FUNCTION; import std.stdio; writeln(convertErrorCode(ERROR_INVALID_FUNCTION)); writeln(convertErrorCode(1234567891)); } -- Simen
Re: Cannot call @system funciton (stdout)
On Saturday, 15 August 2020 at 23:59:36 UTC, Joel wrote: ../../JMiscLib/source/jmisc/base.d(176,2): Error: @safe function jmisc.base.upDateStatus!string.upDateStatus cannot call @system function std.stdio.makeGlobal!"core.stdc.stdio.stdout".makeGlobal /Library/D/dmd/src/phobos/std/stdio.d(4837,20): std.stdio.makeGlobal!"core.stdc.stdio.stdout".makeGlobal is declared here I got around it by avoiding 'stdout'. First, what's wrong with using writeln and friends instead of directly mucking about with stdout? :p stdout is __gshared, so it's available on any thread at any time. That's not @safe, so it's @system. If you know you're not using stdout from multiple threads, or don't care (it might be perfectly safe even though it's possible to misuse), you can use this code: @property File trustedStdout() @trusted { return stdout; } That's a @trusted wrapper that you can call from @safe code. It's not actually safe though, as multiple threads could be using trustedStdout at the same time. In many use cases, this is unlikely to matter, but it's wroth keeping in mind. -- Simen
Re: can't access an alias created inside an if statement
On Wednesday, 5 August 2020 at 09:32:58 UTC, Flade wrote: Thanks! You see it should work but the thing is. I'm using it inside a function. I'm checking for one of the function's parameter (if parameter == false) and it says that "the variable `parameter` cannot be read at compile time. Do you know if there is a way to fix this? As the error message says, the value must be known at compile time. Most likely, you can simply pass it as a template parameter: void fun(bool parameter)(int arg1, string arg2) { static if (parameter) { } } void main() { fun!true(1, "foo"); fun!false(19, "bar"); } -- Simen
Re: can't access an alias created inside an if statement
On Wednesday, 5 August 2020 at 09:05:36 UTC, Flade wrote: I have used an if-else statement to create an alias to avoid code duplication but it doesn't let me access it outside the if statement. Is there a way to solve this? You're probably looking for static if: static if (useAlias) { alias myAlias = getAlias!(); } myAlias foo = getFoo(); What happens is a regular if statement introduces a scope, so anything declared inside it is unavailable outside. static if does not introduce a new scope, and so its contents can be accessed. static if only works with compile-time constant conditions, but aliases are also compile-time constructs, so this should not pose a problem. -- Simen
Re: miscellaneous array questions...
On Tuesday, 21 July 2020 at 13:42:15 UTC, Steven Schveighoffer wrote: On 7/21/20 8:34 AM, Adam D. Ruppe wrote: The others aren't wrong about stack size limits playing some role, but the primary reason is that it is a weird hack for @safe, believe it or not. ... I don't recall exactly when this was discussed but it came up in the earlier days of @safe, I'm pretty sure it worked before then. I think this was discussed, but was not the reason for the limitation. The limitation exists even in D1, which is before @safe: https://digitalmars.com/d/1.0/arrays.html#static-arrays I have stressed before that any access of a pointer to a large object in @safe code should also check that the base of the object is not within the null page (this is not currently done). This is the only way to ensure safety. It seems the limitation was introduced in DMD 0.123, in May 2005: https://forum.dlang.org/post/d61jpa$1m0l$1...@digitaldaemon.com Walter gives some justification in the post immediately following: 1) Gigantic static arrays are often either the result of a typo or are a newbie mistake. 2) Such require a lot of memory for the compiler to handle. Before the OS officially runs out of memory, it goes to greater and greater lengths to scavenge memory for the compiler, often bringing the computer to its knees in desperation. 3) D needs to be a portable language, and by capping the array size a program is more likely to be portable. 4) Giant arrays are reflected in a corresponding giant size for the exe file. 5) There simply isn't a need I can think of for such arrays. There shouldn't be a problem with allocating them dynamically. I admit I thought it was an old optlink limitation, but it seems it's basically arbitrary. -- Simen
Re: What's the point of static arrays ?
On Friday, 10 July 2020 at 10:13:23 UTC, wjoe wrote: However stack memory needs to be allocated at program start. I don't see a huge benefit in allocation speed vs. heap pre-allocation, or is there? I mean 1 allocation vs 2 isn't going to noticeably improve overall performance. You seem to still be thinking of static arrays as the same kind of "thing" as a dynamic array. They're (usually) more like ints or structs than containers: they're generally small, they're often parts of other structures or classes, and they're fairly often the element type of a larger dynamic array. For instance, a bitmap image could be a byte[4][][], with dynamic dimensions 3840x2160. If instead of byte[4] we used byte[], not only would things grind to a halt immediately, we'd also be using massively more memory. When you're using a static array on the stack, it's usually just because it's more convenient to say `int[16] buffer;` than `auto buffer = new int[16];`. The fact it may be faster is mostly a side benefit. Also, even if you did preallocate such a buffer, there's the overhead of remembering how to get to it, the work of setting it up, probably a function call on use, etc. The alternative is terser, built-in, more obvious to maintainers, pretty unlikely to overflow the stack, and very unlikely to be slower. Allocating a multi-MiB static array on the stack is a sign that you're using your screwdriver as a hammer, and there are probably better ways to do what you're trying to do. a[] What happens here exactly ? It creates a dynamic array that points to the data in the static array. It's just shorthand for a[0..$]: unittest { int[4] a = [1,2,3,4]; auto b = a[]; assert(b.length == 4); assert(b.ptr == [0]); auto c = a[0..$]; assert(b is c); } -- Simen
Re: What's the point of static arrays ?
On Thursday, 9 July 2020 at 12:12:06 UTC, wjoe wrote: I'm not considering supposed performance benefits/penalties because these need to be profiled. Considering the many downsides why would I ever want to choose a static over a dynamic array ? Simply put: static arrays are not dynamic arrays, and if you try to use one as the other you're going to be disappointed. Usually, you use static arrays when you interface with something else that does it - generally a file format or a C library. For the most part you're right, you should probably use a dynamic array instead. Now, as for your points: - Can neither grow nor shrink them - Can't append elements - Can't remove elements These are the same as the first point. - Can't slice them - Can't range them Sure you can: unittest { import std.stdio; import std.algorithm; int[10] a = [1,2,3,4,5,6,7,8,9,10]; // Note I'm slicing the static array to use in range algorithms: writeln(a[].map!(b => b+2)); // Slicing works: auto b = a[3..6]; b[] = 7; writeln(a); } - Assignment copies the whole array, as in int[5] a; auto b = a; This is often a factor in choosing a static array. It's not better or worse, just different. And sometimes it's different in exactly the way you need. - Size is limited by stack - Stack overflow issues So allocate your static array on the heap if this is a problem? Some of the cons could be considered a feature. Also GC but it's possible to make a dynamic array implementation which avoids the GC. Basically none of the drawbacks you refer to are actual drawbacks, but instead part of what makes static arrays useful. Static arrays are not a poor man's dynamic arrays, they're a different beast, doing different things. -- Simen
Re: Progress printing with threads?
On Wednesday, 1 July 2020 at 07:52:28 UTC, AB wrote: Hello. I am unsure how to proceed about printing progress in my program. Suppose the program is processing a very big file and is iterating the file's bytes using a for loop. The processing takes several minutes and I want a progress percentage be printed every 2 seconds in this manner: Progress: 0.40% Progress: 3.20% Progress: 5.73% Is it a good idea to std.concurrency.spawn a new thread and pass to it cast(float)i * 100 / fileSize somehow? If not, what's a better way to do this? This example code shows my situation: MmFile input = new MmFile(/* ... */); ulong fileSize= input.length; for (ulong i = 0; i < fileSize; ++i) { // ... } Thanks in advance. If doing the update in the same thread that does the processing is somehow not an option, this works for me: import std.concurrency; import std.stdio; import core.thread; import core.time; void main() { ulong filesize = 1234; ulong i = 0; Tid progress = spawn((shared const(ulong)* p, ulong f){ while (!receiveTimeout(2000.msecs, (int i){ })) { writeln(*p, "/", f, ": ", *p*100.0/f, "%"); } }, cast(shared), filesize); for (; i < filesize; ++i) { // Process } progress.send(0); // Stop } There's a cast to shared there which may be suboptimal, but since the progress thread is only reading it, I would say it's ok. -- Simen
Re: Generating struct members from c structs
On Wednesday, 1 July 2020 at 07:26:44 UTC, Anthony wrote: When doing interop with a c library, is there a way to automatically generate the fields that are needed for a struct? [snip] Is there an easier way though? Dstep is probably what you're looking for: https://github.com/jacob-carlborg/dstep It eats C header files and creates appropriate D files from them. -- Simen
Re: scope guard question
On Tuesday, 30 June 2020 at 12:18:14 UTC, Steven Schveighoffer wrote: I can see where it would be confusing, and it could probably contain an example and clarification. https://issues.dlang.org/show_bug.cgi?id=20997
Re: How to implement Canceleable spawn() from parent
On Tuesday, 30 June 2020 at 13:44:38 UTC, aberba wrote: On Tuesday, 30 June 2020 at 12:48:32 UTC, Simen Kjærås wrote: On Tuesday, 30 June 2020 at 08:15:54 UTC, aberba wrote: On Tuesday, 30 June 2020 at 00:33:41 UTC, Ali Çehreli wrote: 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. So I tried that initially but my (){ writeln(...) } wasn't printing anything in console. Could that be related to stdout buffering? The program kept running though. So I guess the error is elsewhere, but I'm not sure where and how. Yeah, you're right. I changed receiveTimeout() to receive() to try something and forgot to change it back. Jeez, I hate myself. Thanks. So how can I now hide the core.thread.thread_joinAll so the library user doesn't have to type it themselves in main() ? I don't see how that can be done. __gshared Tid mainTid; static this() { if (mainTid.tupleof[0] is null) { mainTid = thisTid; } } static ~this() { if (thisTid == mainTid) { thread_joinAll(); } } The above code does the trick. So, what does it do? __gshared means 'this variable is accessible to all threads'. static this() runs upon creation of any thread including the main thread. Since the main thread will run first*, it gets to store its Tid in mainTid, and every other thread will see a populated mainTid and leave it alone. In the module destructor, which runs after main(), we call thread_joinAll() iff we're the main thread. Now, why should you not do this? Well first, instead of getting a tidy crash you get a process that doesn't end. Second, there's the race conditions described below. Third, there's the principle of least astonishment. D programmers expect that when main() returns, the program will exit shortly(ish), while this zombie could continue running indefinitely. -- Simen *I'm pretty sure this is possibly wrong, if a module constructor spawns a new thread. There's also a possible race condition where newly spawned modules may conceivably not see a properly initialized mainTid.
Re: How to implement Canceleable spawn() from parent
On Tuesday, 30 June 2020 at 08:15:54 UTC, aberba wrote: On Tuesday, 30 June 2020 at 00:33:41 UTC, Ali Çehreli wrote: 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. So I tried that initially but my (){ writeln(...) } wasn't printing anything in console. Could that be related to stdout buffering? The program kept running though. Seems weird. This works great on my machine: import core.time : Duration, msecs; import core.thread : Thread, thread_joinAll; import std.concurrency : spawn, Tid, send, receiveTimeout; import std.stdio : writeln; private struct IntervalStop {} Tid setInterval(Duration dur, void function() fn) { return spawn((Duration d, void function() f){ while (!receiveTimeout(d, (IntervalStop s){})) { f(); } }, dur, fn); } void stopInterval(Tid tid) { tid.send(IntervalStop()); } void main() { auto a = setInterval(1000.msecs, (){ writeln("Hello from spawned thread A"); }); // Stop it before it happens stopInterval(a); Thread.sleep(2000.msecs); auto b = setInterval(1000.msecs, (){ writeln("Hello from spawned thread B"); }); // Let this one run a little Thread.sleep(2500.msecs); stopInterval(b); auto c = setInterval(1000.msecs, (){ writeln("Hello from spawned thread C"); }); // Sending the wrong message doesn't make it happen or stop prematurely c.send("Stop this at once!"); Thread.sleep(2500.msecs); stopInterval(c); thread_joinAll(); } So I guess the error is elsewhere, but I'm not sure where and how. -- Simen
Re: Unused template arguments; what type to use?
On Friday, 26 June 2020 at 13:21:25 UTC, drathier wrote: How can I tell the compiler that I will never create a value of type X, while still being able to write code that uses it? Using void as a template parameter is where I started, but I still need to be able to declare variables inside this unreachable function, like `T foo;` even when `T == void`. Can I get any closer to what I want than an empty struct? Depends on what you care about, I guess. A final abstract class has been my go-to on a few occasions. I'd argue the empty struct is better in most cases, and a forward-declared struct with no implementation might work in some cases. -- Simen
Re: Flagging special conditions on return from a function call
On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote: (1) Assign an unused value for the flag (e.g. -1 when the function returns an int), and return the combined value/flag. This happens in some Phobos algorithms, and might be the most common on this list. (2) Return a tuple with the value and the flag (3) Return a struct or tuple with named value and flag members Would certainly work, but I don't think it's common in D. (4) Set the function return value normally, and put the flag in an "out" variable passed as an argument to the function (5) Return the flag, and put the value in an "out" variable passed to the function (i.e. the reverse of #4) Both of these happen. I don't know which is more common. In C# these are probably the most common way (except for exceptions) to signal these cases. (6) Use two separate functions, one that returns the value, and another that can be called afterwards to check the flag (like eof(), for example) (7) Use a side effect and set a designated global variable Global variables are frowned upon, so probably not this. :p One thing I feel is missing here (perhaps because std.variant.Algebraic is egregious): (8) Return a Maybe!T or Algebraic!(T, ErrorCode) It's what I personally would prefer, but I have only rarely seen it in D code. Given a properly written Maybe, this could enforce proper handling of the error case, either by throwing on trying to get at Maybe!T.getValue when it's holding None, or by presenting an interface that only compiles when both cases are covered, like fun().match((T t) => t, () => Error()). -- Simen
Re: Parallel array append using std.parallelism?
On Thursday, 18 June 2020 at 14:43:54 UTC, H. S. Teoh wrote: I have an array of input data that I'm looping over, and, based on some condition, generate new items that are appended onto a target array (which may already contain data). Since the creation of new items is quite expensive, I'm thinking to parallelize it with parallel foreach. To avoid data races, my thought is for each generated item to be appended to thread-specific temporary arrays, that after the parallel foreach get sequentially appended to the target array. Something like this: Item[] targetArray = ...; // already contains data Item[][nThreads] tmp; foreach (elem; input.parallel) { if (condition(elem)) { auto output = expensiveComputation(elem); tmp[threadId] ~= output; } } foreach (a; tmp) targetArray ~= a; Is there an easy way to achieve this with std.parallelism? I looked over the API but there doesn't seem to be any obvious way for a task to know which thread it's running in, in order to know which tmp array it should append to. If possible I'd like to avoid having to manually assign tasks to threads. There's an example of exactly this in std.parallelism: https://dlang.org/phobos/std_parallelism.html#.TaskPool.workerIndex In short: Item[] targetArray = ...; // already contains data // Get thread count from taskPool Item[][] tmp = new Item[][taskPool.size+1]; foreach (elem; input.parallel) { if (condition(elem)) { auto output = expensiveComputation(elem); // Use workerIndex as index tmp[taskPool.workerIndex] ~= output; } } foreach (a; tmp) targetArray ~= a; -- Simen
Re: Should a parser type be a struct or class?
On Wednesday, 17 June 2020 at 11:50:27 UTC, Per Nordlöw wrote: Should a range-compliant aggregate type realizing a parser be encoded as a struct or class? In dmd `Lexer` and `Parser` are both classes. In general how should I reason about whether an aggregate type should be encoded as a struct or class? The heuristic I use is 'do I need polymorphism?' If no, it's a struct. Another thing that may be worth considering is reference semantics. The latter is easy to do with a struct, while polymorphism is generally a class-only thing (but check out Tardy, which Atila Neves recently posted in the Announce group). I would say I basically never use classes in D - pointers and arrays give me all the reference semantics I need, and polymorphism I almost never need. -- Simen
Re: `this` template params for struct not expressing constness.
On Monday, 8 June 2020 at 09:08:40 UTC, adnan338 wrote: On Monday, 8 June 2020 at 08:10:19 UTC, Simen Kjærås wrote: On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote: Self* searchTree(this Self)(auto in ref T item) const { if ( is null) return null; if (this.item == item) return return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } This method is const, which means 'this' is const, while Self is not. What you're looking for here is inout (https://dlang.org/spec/function.html#inout-functions): auto searchTree()(auto in ref T item) inout { if ( is null) return null; if (this.item == item) return return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } -- Simen Thank you. Few followup questions, if you don't mind. 1. What does that blank template parameter mean? Just forces the function to be a template. The only reason for this is it's required for auto ref to work, which you may or may not need on that function. 2. Since `inout` acts as a wildcard for immutable/const/non-const qualifiers, what should I do to have the compiler ensure that my method does not mutate a non-const tree inside the body? Inside inout functions, `this` is treated as const - any attempt to modify it should give a compile error. Since D const is transitive, anything reachable from `this` is also treated as const. If you're able to mutate a non-const tree inside the body, there's a bug in the compiler. -- Simen
Re: `this` template params for struct not expressing constness.
On Monday, 8 June 2020 at 07:35:12 UTC, adnan338 wrote: Self* searchTree(this Self)(auto in ref T item) const { if ( is null) return null; if (this.item == item) return return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } This method is const, which means 'this' is const, while Self is not. What you're looking for here is inout (https://dlang.org/spec/function.html#inout-functions): auto searchTree()(auto in ref T item) inout { if ( is null) return null; if (this.item == item) return return (this.item < item) ? this.right.searchTree(item) : this.right.searchTree(item); } -- Simen
Re: how to append (ref) int[] to int[][]?
On Monday, 8 June 2020 at 06:13:36 UTC, mw wrote: Hi, I have this program: import std.stdio; void f(ref int[] arr) { arr ~= 3; } void main() { int[][] arrs; int[] arr; foreach (i; 0 .. 3) { arr = new int[0]; arrs ~= arr; //(a) [[], [], []] f(arr); // arrs ~= arr; //(b) [[3], [3], [3]] } writeln(arrs); } This program will print out [[], [], []]. If I comment out (a), and use (b), it will print out [[3], [3], [3]] So based on this behavior, looks like "~=" will append a copy of `arr`; but what I really want in (a) is append `ref arr` and output [[3], [3], [3]], i.e. the real `arr` be appended instead of its copy. I have to say this semantics surprised me. I tried to change arrs' decl to: (ref (int[]))[] arrs; // the intended semantics I want But I got compiler error out: "found ( when expecting function literal following ref". 1) I'm wondering how to achieve what I want? and 2) why "~=" here will append a copy rather than the real `arr` itself to arrs? Arrays (technically, slices) in D are essentially this struct: struct Array(T) { T* ptr; size_t length; // operator overloads } So when you have int[][], each element of the outer array is an Array!int. These, as simple structs, are copied about, so that changing one does not change another. The simple solution here is to call f not on arr, but on arrs[$-1] (the last element of arrs). If that is not possible you will need arrs to be an int[]*[]. -- Simen
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Wednesday, 3 June 2020 at 15:25:51 UTC, Paul Backus wrote: On Wednesday, 3 June 2020 at 13:24:17 UTC, Basile B. wrote: This is because the template parameter must be resolved to a valid symbol or type. This version other version bypass the problem: --- enum Exists(string s) = is(typeof(mixin(s))); void main() { static if (!Exists!"foo") int foo; foo = 42; } --- Fails if the symbol in question is the name of a type. struct Foo {} enum Exists(string s) = is(typeof(mixin(s))); static assert(Exists!"Foo"); // false What you actually want is something like this: enum Exists(string s) = __traits(compiles, { mixin("alias _ = ", s, ";"); }); And they both fail if the thing you refer to isn't available in the scope where Exists is defined. I believe this covers most cases, but there may very well be corner cases I haven't considered: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } // Handles values: int global; unittest { int local; { int outOfScope; } static assert(mixin("local".exists)); static assert(mixin("global".exists)); static assert(!mixin("outOfScope".exists)); } // And types: struct Global {} unittest { struct Local {} { struct OutOfScope; } static assert(mixin("Global".exists)); static assert(mixin("Local".exists)); static assert(!mixin("OutOfScope".exists)); } // But not expressions: static assert(!mixin("1+2".exists)); // Correctly fails for missing declarations: static assert(!mixin("nowhere".exists)); Like Stefan said though, we're quite a bit off from the original request - the above certainly shouldn't be faster than drathier's original code. The only advantage I see is that it might read a little clearer. -- Simen
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Wednesday, 3 June 2020 at 09:39:34 UTC, Basile B. wrote: You can use this template: enum Exists(alias T) = is(typeof(T)); I don't know if there's a faster way bu this technic is used, notatbly in phobos, to workaroud issues of double declaration in `static foreach` enum Exists(alias T) = is(typeof(T)); static assert(!Exists!bar); // undefined identifier bar -- Simen
Re: Unable to access a variable declared inside an if statement (Error: is shadowing variable)
On Wednesday, 27 May 2020 at 11:03:51 UTC, BoQsc wrote: I'm lacking knowledge on how to achieve what I want and getting an error. What is the correct way to do what I tried to achieve in this code? Everything was intuitive until I started to add notice variable to the writeln. Rdmd says variable `notice` is shadowing variable. if (driveLetter.exists){ auto directory = "/Backup"; if ((driveLetter ~ directory).exists){ auto notice = "Backup directory exists."; } writeln(driveLetter, notice); } Variables only live in a specified scope, starting from where they are declared, and ending when they reach the '}' indicating the end of said scope. In you case, 'notice' only lives inside the if ((driveLetter ~ directory).exists) scope, and doesn't exist outside. In order to fix this, you will need to declare it outside: if (driveLetter.exists) { auto directory = "/Backup"; auto notice = "Backup directory does not exist."; if ((driveLetter ~ directory).exists) { notice = "Backup directory exists."; } writeln(driveLetter, notice); } This also makes it clearer what value 'notice' will have when the backup directory doesn't exist - in your case you haven't assigned it any value in that case. -- Simen
Re: opEquals @safe is ignored
On Sunday, 24 May 2020 at 08:57:28 UTC, Luis wrote: dmd ignores @trusted or @safe on opEquals, throwing this error : onlineapp.d(27): Error: @safe function onlineapp.__unittest_L24_C7 cannot call @system function object.opEquals An override @system or @trusted function can't be @safe, or I it a bug ? Also, how will this be affected by DIP1028 ? Looking at the output, it's actually druntime's opEquals that can't be called. That's the global function that ensure opEquals is called on both sides of the comparison, and it's not @safe. This makes classes even worse to use in D than, and I'm not sure how to properly handle this. If we make it @trusted, suddenly I can call @system opEquals from @safe functions without issue. Root cause is, classes in D all inherit from Object, which has some defaults that aren't always what you want. It seems DIP1028 will make your code automatically compile, along with this: class C { override bool opEquals(Object o) @system { *cast(int*)123456 = 3; return true; } } @safe void mySafeFunction() { assert(new C() == new C()); } -- Simen
Re: Assignment of tuples
On Wednesday, 20 May 2020 at 13:51:05 UTC, Steven Schveighoffer wrote: Please file an issue. https://issues.dlang.org/show_bug.cgi?id=20850 -- Simen
Re: Bug?
On Monday, 11 May 2020 at 12:44:45 UTC, Jack Applegame wrote: On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote: UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply. But in this case the error should be displayed for lines 4 and 5, not 11. Line 11 contains a call to a member function, not UFCS. In addition, if you add the parentheses, then it works: assert(rng.front() == '1'); You're right, and it absolutely seems the call on lines 4 and 5 work correctly. Instead, the compiler is confused by the presence of two different overloads for front in Range!T, and doesn't attempt to call the one it can call. We get the exact same behavior here: struct S { int gun()(int i) { return 0; } alias fun = gun; int fun() { return 1; } } static assert(S().fun == 1); Filed here: https://issues.dlang.org/show_bug.cgi?id=20821 -- Simen
Re: What could this be?
On Monday, 11 May 2020 at 11:20:51 UTC, Joel wrote: I'm gotten stuck with this error - "..is not visible from module.." Without some code it's hard to say exactly, but this generally means you're referencing a private symbol in a different module: module foo; private struct S {} module bar; import foo; foo.S s; // foo.S is not visible from module bar -- Simen
Re: How does a free list work?
On Saturday, 9 May 2020 at 19:54:44 UTC, Pavel Shkadzko wrote: I have been reading about memory management in D on https://wiki.dlang.org/Memory_Management and found an example of a free list (pattern?): "Free lists are a great way to accelerate access to a frequently allocated and discarded type.". Here is the example of free list: --- class Foo { static Foo freelist; // start of free list Foo next; // for use by FooFreeList static Foo allocate() { Foo f; if (freelist) { f = freelist; freelist = f.next; } else f = new Foo(); return f; } static void deallocate(Foo f) { f.next = freelist; freelist = f; } } --- Do I understand correctly that by switching between static and non-static Foo we keep the object from being garbage collected by the GC? So in a situation when I need to create an object and then discard it, I can implement this pattern to use memory more efficiently. Also, it's a little strange that since both f and freelist are null we are basically doing null = null in first if condition. The GC keeps a list of roots - that is, objects that are known to be active and should not be collected. The static freelist is one of those - since it's static it should of course never be collected. From these roots, the GC scans all referenced objects recursively, and finally releases all memory that has not been scanned (and that thus have no path of pointers leading from a root to that memory). Since any call to new will check if memory is available, and potentially trigger a GC collection, it can be expensive, so if you can avoid allocating and deallocating objects a lot, it's an easy optimization. To more clearly show this, here's some code that prints what it does: import std.stdio : writeln; class Foo { static Foo freelist; Foo next; string name; this(string name) { this.name = name; } ~this() { writeln("GC collecting ", name); } static Foo allocate(string name) { if (freelist) { auto f = freelist; freelist = f.next; writeln("Fetching ", f.name, " from freelist, changing name to ", name); f.name = name; return f; } writeln("Nothing in freelist, allocating new ", name); return new Foo(name); } static void deallocate(Foo f) { writeln("Adding ", f.name, " to freelist, freelist.next points to ", freelist ? freelist.name : "(null)"); f.next = freelist; freelist = f; } } unittest { Foo a = Foo.allocate("A"); Foo b = Foo.allocate("B"); Foo c = Foo.allocate("C"); Foo.deallocate(a); Foo.deallocate(b); a = null; b = null; c = null; import core.memory; GC.collect(); // For some reason I need to call this twice for C to be collected? GC.collect(); Foo d = Foo.allocate("D"); Foo e = Foo.allocate("E"); Foo f = Foo.allocate("F"); } The above code creates this output: Nothing in freelist, allocating new A Nothing in freelist, allocating new B Nothing in freelist, allocating new C Adding A to freelist, freelist.next points to (null) Adding B to freelist, freelist.next points to A GC collecting C Fetching B from freelist, changing name to D Fetching A from freelist, changing name to E Nothing in freelist, allocating new F 1 unittests passed GC collecting E GC collecting D GC collecting F Here's what it does in more words: For the first call to allocate(), the freelist is null, and a new Foo is created in the 'else' path, before being returned. Nothing is assigned to freelist or next. The second and third call does the exact same thing, since nothing has been assigned to the freelist. We then deallocate a, which assigns it to the freelist. Next we deallocate b, which sets b's 'next' field to point at a, and sets freelist to point at b. We then set a, b, and c to null, so those references will no longer keep the Foos alive. Then we call GC.collect, which finds that the Foo previously stored in b is now in freelist, and thus will be kept. The Foo that was in a is referenced by freelist.next, and will also live. The foo in c, however, is no longer referenced anywhere, and will be collected. This shows the main point of the freelist - to ensure the objects aren't collected by the GC - but what happens afterwards? When we allocate d, freelist points at the Foo that used to be stored in b, so it is returned from allocate(), and the freelist is changed to point to the Foo that used to be in a. Allocating e there's still something in freelist, so it is returned. At this point the freelist is empty, and allocating f creates a new Foo, just like when we allocated a, b, and c. --
Re: XMM Intrinsics
On Friday, 8 May 2020 at 13:09:49 UTC, kinke wrote: On Friday, 8 May 2020 at 12:49:00 UTC, Simen Kjærås wrote: How would I go about calling _mm_* functions in D in a way that is portable between D compilers? You would use core.simd: Nope one wouldn't, because that horrible interface isn't supported by LDC, and I guess GDC neither. The intel-intrinsics dub package aims to provide a compiler-independent layer: https://code.dlang.org/packages/intel-intrinsics TIL, thanks! :) -- Simen
Re: XMM Intrinsics
On Friday, 8 May 2020 at 12:38:51 UTC, Marcio Martins wrote: Hi, I am building a CRC32C implementation using SSE for D, because I couldn't find any readily available :[ However, I am unable to find any documentation regarding which SSE instructions are available and how I could use them in D. I can see core.simd can't seem to make any use of it. How would I go about calling _mm_* functions in D in a way that is portable between D compilers? You would use core.simd: https://dlang.org/library/core/simd.html Sadly, the supported instructions are not documented on that page, and you'll need to look at the source to get at them: https://github.com/dlang/druntime/blob/master/src/core/simd.d#L85-L384 (I'll file a bug on this) There's a bit more info on D SIMD instructions here: https://dlang.org/spec/simd.html -- Siomen
Re: Is there a way to benchmark/profile portably?
On Thursday, 7 May 2020 at 10:21:07 UTC, Dukc wrote: Is there some way to measure the performance of a function so that the results will be same in different computers (all x86, but otherwise different processors)? I'm thinking of making a test suite that could find performance regressions automatically. I figured out Bochs[1] could be used for that, but it seems an overkill for me to install a whole virtual operating system just to benchmark functions. Does anybody know more lightweight way? [1] http://bochs.sourceforge.net/ If I understand correctly, you want to measure how many cycles pass, rather than clock time? If so, it seems perf can do that: https://perf.wiki.kernel.org/index.php/Tutorial -- Simen
Re: variant visit not pure?
On Thursday, 7 May 2020 at 09:22:28 UTC, learner wrote: Good morning, Is there a reason why std.variant.visit is not inferring pure? ``` void test() pure { Algebraic!(int, string) alg; visit!( (string) => 0, (int) => 0)(alg); } Error: pure function test cannot call impure function test.visit!(VariantN!(16LU, int, string)).visit ``` std.variant.Algebraic is essentially a std.variant.Variant in different clothes. Variant is very flexible, and this comes at a cost (and isn't used in Algebraic, meaning you pay for things you don't use). Like Dukc said, you might be better off with Taggedalgebraic or SumType (https://code.dlang.org/packages/sumtype). Variant uses runtime type information to hold *any* type. Since Algebraic specifically only holds a few types, all the framework that's in place for Variant is wasted on Algebraic, and makes it less useful and less performant. -- Simen
Re: Bug?
On Tuesday, 5 May 2020 at 04:02:06 UTC, RazvanN wrote: truct K { ~this() nothrow {} } void main() { static class C { this(K, int) {} } static int foo(bool flag) { if (flag) throw new Exception("hello"); return 1; } try { new C(K(), foo(true)); } catch(Exception) { } } Result: object.Exception@test.d(18): hello If the destructor of K is not marked nothrow the code does not throw an exception. Is this a bug or am I missing something? Surely the above code, which silently discards the exception, does not print "hello"? Regardless, I ran your code with writeln inside the catch(), and without the try-catch entirely, with and without nothrow on K's destructor. I am unable to replicate the issue on my computer with DMD 2.091.0, as well as on run.dlang.io. Is something missing in your code here? -- Simen
Re: Aliasing current function template instance
On Friday, 1 May 2020 at 20:28:58 UTC, Jean-Louis Leroy wrote: Is it possible, inside a function template, to create an alias to the instantiated function? IOW the equivalent of __FUNCTION__, but yielding an alias? The closest I came is: import std.string; import std.traits; void foo(T)(lazy T) { mixin( "alias thisFunction = ", __FUNCTION__[0..__FUNCTION__.lastIndexOf('.')], ";"); pragma(msg, Parameters!thisFunction); } void main() { foo(0); foo(""); } dmd -c aliasthisfunction.d (lazy int) (lazy string) ...but (unsurprisingly) this fails in presence of overloads. I.e. if I throw in: void foo(T)(int, T); ...then I get: aliasthisfunction.d(6): Error: template `aliasthisfunction.foo` matches more than one template declaration: aliasthisfunction.d(4): `foo(T)(lazy T)` and aliasthisfunction.d(20): `foo(T)(int, T)` ... Something I have overlooked? Any ideas? This should work: alias context(alias a) = __traits(parent, a); void fun() { alias ctx = context!({})(); } {} becomes a lambda inside fun(), so it's parent is fun(). The same could be done by introducing a symbol explicitly, but that pollutes the namespace. This template works inside functions, methods, lambdas, modules, structs, classes and interfaces. -- Simen
Re: Can't recreate a range?
On Thursday, 30 April 2020 at 13:23:25 UTC, Paul Backus wrote: On Thursday, 30 April 2020 at 13:04:47 UTC, Casey wrote: Here's a minimal code example that duplicates the issue: import std.array, std.range, std.stdio, std.traits, std.string; auto readStream(Range)(auto ref Range r) if (isInputRange!(Unqual!Range)) { struct StreamRange(Range) { alias R = Unqual!Range; R _input; auto buff = appender!string; Using a default value like this means that it will be shared among all instances of the struct. Instead, you should set `buff = appender!string` in the constructor, so that each struct will have its own appender. Yup, that's the one. No need to assign it at all, in fact - the line can be replaced with Appender!string buff; And things just work. -- Simen
Re: Can't recreate a range?
On Wednesday, 29 April 2020 at 20:43:20 UTC, Casey wrote: void popFront() { } I mean, it might be you messed up in posting this, but having an empty popFront and expecting it to do something is a tad optimistic. Apart from that, it seems like the code should do what you want it to. What's the value of count when the code asserts? I'm afeared we'll need some code that actually compiles and shows off the issue to give any more answers. -- Simen
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 09:16:58 UTC, user1234 wrote: The static checker doesn't see your free funcs because to do so it would have to import the whole module. (is it possible to do that ? no idea.) Of course it's possible! :) We can find the context of R (in this case, the module) with __traits(parent), and import that: mixin("import "~__traits(parent, R).stringof["module ".length..$]~";"); However, doing that in isInputRange doesn't help much. First, all other range functions would have to do it, and second, just importing into function scope doesn't enable UFCS lookup. Also your signature for the primitives are quite unusual (i.e not idiomatic). Usually they dont take param. Usually we pass a type that contains the member funcs matching to IsIntputRange. You can see a good counterexample to this in https://dlang.org/library/std/range/primitives/pop_front.html, which defines popFront for regular arrays. However, that is the one and only counterexample I know of. Of course, nothing stops us from defining our own front, popFront and friends that combine the two approaches above: template front(R) { auto front(R r) { return __traits(getMember, __traits(parent, R), "front")(r); } } template popFront(R) { auto popFront(R r) { return __traits(getMember, __traits(parent, R), "popFront")(r); } } template empty(R) { auto empty(R r) { return __traits(getMember, __traits(parent, R), "empty")(r); } } We could conceivably add these to std.range.primitives (probably adding some constraints first), and suddenly UFCS ranges are possible! (I am as of yet not convinced that we should, though) -- Simen
Re: Can’t use UFCS to create InputRange?
On Wednesday, 29 April 2020 at 08:34:53 UTC, Ogi wrote: struct R {} int front(R r) { return 42; } void popFront(R r) {} bool empty(R r) { return false; } void main() { import std.range.primitives : isInputRange; static assert(isInputRange!R); } Error: static assert: `isInputRange!(R)` is false What’s going on here? The template IsInputRange is in the std.range.primitives module, and thus can't see the front, popFront and empty definitions in your module. -- Simen
Re: How convert String to Hex?
On Saturday, 18 April 2020 at 15:47:38 UTC, Marcone wrote: How convert String to Hex? Example: string text = "Hello World"; // Converted to Hex = 48656c6c6f20576f726c64 import std.format : format; string hex = format("%(%2x%)", "Hello World"); import std.stdio : writeln; writeln(hex); A bit of explanation: %( %) is a range formatting specifier, and basically means "format each element of the range with the format specifier between these two symbols". In other words, it's the equivalent of "Hello World".map!(c => format("%2x", c)).joiner. -- Simen
Re: Extracting user defined attributes on function parameters
On Saturday, 18 April 2020 at 09:19:48 UTC, Simen Kjærås wrote: On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh wrote: I wonder if the ultimate cause of the above case is ultimately caused by the change to import semantics that hid private symbols from outside the module. Perhaps something, somewhere, is triggering an illegal access of a private symbol, which percolates up the call/instantiation stack and causing what appears to be a strange compiler discrepancy. Not unlikely. Importing the module defining S in the module defining ParameterDefaults does indeed make things compile. Hiding S by making it private makes the error return. It's not about private. Or even if it is, there's other issues. Proof: struct A { struct S {} void f(@S int = 3); pragma(msg, Issue20744!f); } template Issue20744(func...) { static if (is(typeof(func[0]) PT == __parameters)) { alias Issue20744 = (PT args) {}; } } -- Simen
Re: Extracting user defined attributes on function parameters
On Wednesday, Friday, 17 Apr 2020 17:45:47 UTC, H. S. Teoh wrote: I wonder if the ultimate cause of the above case is ultimately caused by the change to import semantics that hid private symbols from outside the module. Perhaps something, somewhere, is triggering an illegal access of a private symbol, which percolates up the call/instantiation stack and causing what appears to be a strange compiler discrepancy. Not unlikely. Importing the module defining S in the module defining ParameterDefaults does indeed make things compile. Hiding S by making it private makes the error return. (for whatever reason your message isn't visible in the web interface) -- Simen
Re: Extracting user defined attributes on function parameters
On Friday, 17 April 2020 at 16:54:42 UTC, Adam D. Ruppe wrote: This part seems fine... pragma(msg, ParameterDefaults!f.stringof); It is this, specifically, that causes the problem. Replace it with: void main() { import std.stdio; writeln(ParameterDefaults!f.stringof); } and it is fine. So pragma(msg) is doing something really weird, the bug doesn't appear to be in Phobos per se, I think it is the compiler doing the wrong thing, it seems to me it works inside a function scope but not at module scope.. It's even more fascinating - the issue doesn't occur if ParameterDefaults is defined in the same module that it's used in, and it works if there's a type with the same name as the UDA. Reducing the code as much as I can, I get this: struct S {} void f(@S int = 3); pragma(msg, ParameterDefaults!f.stringof); template ParameterDefaults(func...) { import std.traits : FunctionTypeOf; static if (is(FunctionTypeOf!(func[0]) PT == __parameters)) { enum ParameterDefaults = (PT[0..1] args) @trusted { return *&(args[0]); }(); } } The above code works, and prints "3". If you move ParameterDefaults to a different module, something like this: - import bar; struct S {} void f(@S int = 3); pragma(msg, ParameterDefaults!f.stringof); - module bar; template ParameterDefaults(func...) { static if (is(typeof(func[0]) PT == __parameters)) { enum ParameterDefaults = (PT[0..1] args) @trusted { return *&(args[0]); }(); } } - Then you get an error message about 'undefined identifier S'. Add some kind of S to bar, and you get an error message about S not being readable at compile-time or things just work if it is readable. It seems the UDA is being looked up in the wrong context. -- Simen
Re: Checked!({short, ushort, byte, ubyte}, Throw): compilation fails
On Friday, 17 April 2020 at 08:59:19 UTC, kdevel wrote: On Friday, 17 April 2020 at 04:29:06 UTC, Meta wrote: Unlike C/C++, char is not a numeric type in D; It's a UTF-8 code point: Thanks, it's a code /unit/. main reads now: void main () { bar!ubyte; bar!byte; bar!ushort; bar!short; bar!uint; bar!int; bar!ulong; bar!long; } and dmd complains: The problem is, short/short gives an int answer: unittest { import std.experimental.checkedint; Checked!(short, Throw) a; pragma(msg, typeof(a/a)); } So, in your code you get this situation: unittest { import std.experimental.checkedint; Checked!(int, Throw) a; Checked!(short, Throw) b = a; } And assigning from an int to a short may discard data, so it's statically disallowed by Checked. This is a deliberate design choice, and the appropriate way to handle it is with a cast: unittest { import std.experimental.checkedint; Checked!(int, Throw) a = 65535; Checked!(short, Throw) b = cast(short)a; } The above code will throw when casting (before the assignment), because 65535 can't fit in a short. You also get a deprecation message, about an integral promotion not being performed. I believe the result is correct and the warning can be ignored. -- Simen
Re: Find the heir.
On Sunday, 29 March 2020 at 14:04:53 UTC, TodNaz wrote: Hello! class A { ... } class B : A { ... } class C : A { ... } A example1; B example2 = new B(...); A = example2; auto heir = A.whoheir(); /// The question in this code is: is it possible to track the class inheritor? Or is it beyond D? Sorry if the question is fool ... The question is a bit unclear - what is whoheir expected to return? This is one way that may or may not fulfill your requirements: module foo; class A { string whoheir() { return typeid(this).name; } } class B : A {} class C : A {} unittest { A a = new B(); assert(a.whoheir == "foo.B"); a = new C(); assert(a.whoheir == "foo.C"); } -- Simen
Re: Get symbols (and/or UDAs) of subclass from superclass
On Sunday, 15 March 2020 at 20:18:03 UTC, James Blachly wrote: I would like to programmatically retrieve members of a subclass to create a self-documenting interface. I am afraid that my approach is not possible due to need for compile time __traits / std.traits, and runtime typeinfo. My proposed approach is as follows: class Base { string whatever; string toString() { // loop over __traits(allMembers, typeof(this)) or getSymbolsByUDA, etc. } } /// There may be a dozen Derived classes class Derived1 : Base { @Config("a name", "a description") float probability; } class Derived2 : Base { @Config("another", "more description") int replicates; } ... There's no built-in way to do this - toString() doesn't know what derived classes exist, and more could be added from other modules and even dynamically loaded libraries. Now, there are ways to do something somewhat like it. I would suggest creating an abstract method in the base class, that derived class would have to override, and use a template this argument to get the correct type for __traits(allMembers) to operate on: class Base { override string toString() { return toStringImpl(); } abstract string toStringImpl(); string toStringBase(this That)() { // foreach (e; __traits(allMembers, That) {...} } } class Derived : Base { override string toStringImpl() { return this.toStringBase(); } } Since toStringImpl will always call toStringBase, this could perhaps better be modeled with a template mixin: mixin template DerivedToString() { override string toStringImpl() { return this.toStringBase(); } } class Derived2 : Base { mixin DerivedToString!(); } This way, you can have all the logic of toString in the base class, and the only thing a subclass will have to include is one line for the mixin. In addition, since toStringImpl is abstract, the implementer of a subclass will get a compile-time error if he or she forgets to do either the mixin or override toStringImpl themselves. -- Simen
Re: A set type implemented as an AA wrapper
On Thursday, 12 March 2020 at 08:51:24 UTC, mark wrote: I use sets a lot and since I believe that D's rbtree is O(lg n) for add/remove/in and that D's AA is O(1) for these, I want to implement a set in terms of an AA. Below is the code I've got so far. It allows for add and remove. However, it has three problems (that I know of): XXX: I need to use an if on the struct to restrict T to be a type that supports toHash and opEquals (i.e., to be a valid AA key) I'd suggest simply testing if an AA with that key type is valid: struct AAset(T) if (is(int[T])) YYY: The range() method is clearly not good D style but I don't know how to support foreach (item; aaset) ... As Ferhat points out, you could use opApply for this. There's also the option of implenting the range primitives front, popFront() and empty. However, the easiest solution is the one you've already chosen, combined with alias this: struct AAset(T) if (is(int[T])) { // stuffs... auto range() { return set.byKey; } alias range this; } ZZZ: I can't figure out how to support the in operator. 'in' for AAs returns a pointer to the value it finds, or null if no item is found. This pointer does not implicitly convert to bool when returned from a function, so you need to compare it to null: bool opBinaryRight(string op)(T lhs) { static if (op == "in") return (lhs in set) != null; else static assert(0, "operator " ~ op ~ " not supported"); } I would also suggest using a template specialization instead of static if and static assert: bool opBinaryRight(string op : "in")(T lhs) { return (lhs in set) != null; } -- Simen
Re: Aliases to mutable thread-local data not allowed [testable source code]
On Wednesday, 11 March 2020 at 12:43:28 UTC, mark wrote: On Wednesday, 11 March 2020 at 12:22:21 UTC, Simen Kjærås wrote: On Wednesday, 11 March 2020 at 09:29:54 UTC, mark wrote: [snip] Fascinating. It works just fine when compiling for 32-bit targets with DMD on Windows, but not for 64-bit targets, nor when compiling with LDC. Apparently, this difference is due to DMD supporting 80-bit reals, and thus giving a different size to Variant (VariantN!20 on DMD on Windows, VariantN!16 or VariantN!32 elsewhere). There's a bug in VariantN that then causes the compilation to fail (https://issues.dlang.org/show_bug.cgi?id=20666). The issue at hand then, is that Deb is too big until that issue if fixed. The simple solution to this is to allocate Deb on the heap with new and pass pointers instead of instances directly. Since you are already calling .dup whenever you pass a Deb somewhere, you can simply modify .dup to return a Deb* and the receive function to receive a Deb*, and I think you should be good to go. I did that and it compiles & runs, but no Debs get added to the collection. See https://github.com/mark-summerfield/d-debtest-experiment -- the 'mto' version is the one with your fixes. Yeah, I forgot we cast to immutable to be able to send, so receive has to receive immutable(Deb)*, after which you can call deb.dup to get a mutable copy: receive( (immutable(Deb)* deb) { debForName[deb.name] = deb.dup; }, (DoneMessage m) { jobs--; } ); -- Simen
Re: Aliases to mutable thread-local data not allowed [testable source code]
On Wednesday, 11 March 2020 at 09:29:54 UTC, mark wrote: Hi Simen, I think you must have done something else but didn't mention to get it to compile. I did the exact changes you said and it wouldn't compile. Here's what I get with changes mentioned below (with new full source): Fascinating. It works just fine when compiling for 32-bit targets with DMD on Windows, but not for 64-bit targets, nor when compiling with LDC. Apparently, this difference is due to DMD supporting 80-bit reals, and thus giving a different size to Variant (VariantN!20 on DMD on Windows, VariantN!16 or VariantN!32 elsewhere). There's a bug in VariantN that then causes the compilation to fail (https://issues.dlang.org/show_bug.cgi?id=20666). The issue at hand then, is that Deb is too big until that issue if fixed. The simple solution to this is to allocate Deb on the heap with new and pass pointers instead of instances directly. Since you are already calling .dup whenever you pass a Deb somewhere, you can simply modify .dup to return a Deb* and the receive function to receive a Deb*, and I think you should be good to go. -- Simen
Re: Aliases to mutable thread-local data not allowed [testable source code]
On Tuesday, 10 March 2020 at 20:03:21 UTC, mark wrote: I've managed to make a cut-down version that's < 170 LOC. It needs to be run on Debian or a Debian-based Linux (e.g., Ubuntu). Hopefully this will help someone understand and be able to help! This took some time figuring out. Turns out, std.concurrency.spawn won't take a delegate as its callable argument. There are sensible reasons for this - delegates have a context that is not guaranteed to be immutable, so allowing delegate callables could lead to mutable aliasing. I've filed an issue to improve documentation and error messages: https://issues.dlang.org/show_bug.cgi?id=20665 However, knowing that some things are impossible do not necessarily help us figure out what we can do to fix the problem, and the good news is, the problems can be fixed. Since the problem is we're giving a delegate where the API expects a function, we can simply turn it into a function. In the code you've given, that means making readPackageFile and readPackageLine static. This make spawn() run as it should. In addition, there's a problem with this line in receive(): (DoneMessage) { jobs--; } That looks sensible, but since DoneMessage doesn't have a name, it is parsed as a templated function taking one argument of unspecified type and called DoneMessage. For some reason, templates passed as function arguments show up in compiler output as 'void', giving this weird error message: template std.concurrency.receive cannot deduce function from argument types !()(void delegate(Deb deb) pure nothrow @safe, void) The solution here is to simply give DoneMessage a name: (DoneMessage d) { jobs--; } With those changes, things at least compile. Now it's up to you to ensure the semantics are correct. :) One last thing: you're passing parentTid around, and that's not actually necessary - std.concurrency.ownerTid does the exact same thing, and is available even if not explicitly passed anywhere. -- Simen
Re: Aliases to mutable thread-local data not allowed
On Tuesday, 10 March 2020 at 08:13:19 UTC, mark wrote: I have this struct: struct Deb { string name; ... Unit[string] tags; // set of tags Deb dup() const { Deb deb; deb.name = name; ... foreach (key; tags.byKey) deb.tags[key] = unit; return deb; } } void readPackageFile(Tid parentTid, string filename) { // (some code elided) try { Deb deb; auto file = File(filename); foreach(lino, line; file.byLine.enumerate(1)) readPackageLine(parentTid, filename, lino, line, deb); // readPackageLine also calls send with same code as AAA below if (deb.valid) send(parentTid, deb.dup); // AAA /home/mark/opt/ldc2-1.20.0-linux-x86_64/bin/../import/std/concurrency.d(625,5): Error: static assert: "Aliases to mutable thread-local data not allowed." Is there any nice solution to this? Surely it is a common pattern to read multiple files and create lots of data items to be merged into a collection? As the error message hints at, the problem is Deb may hold references to data that is shared with other objects on the thread from which it originates. Since you know this is not the case, even if the compiler can't prove it, you can safely cast your Deb to immutable: if (deb.valid) send(parentTid, cast(immutable)deb.dup); In fact, even the .dup is unnecessary here, since no data is shared with other objects, so you can simply write send(parentTid, cast(immutable)deb);. (Note on this point: since you have not included all your code, it could be other parts create shared mutable state, in which case .dup is necessary, and if badly written may not be sufficient. -- Simen
Re: @property with opCall
On Monday, 9 March 2020 at 09:25:31 UTC, Calvin P wrote: Is this a bugs ? == struct A { ref auto opCall(string tmp) scope return { return this; } } struct B { A _a; @property ref auto a() scope return { return _a; } } extern(C) int main(){ A a; a("a")("b"); B b; b.a("a")("b"); // Error: function test_opCall.B.a() is not callable using argument types (string) return 0; } == I has to use b.a()("a")("b") to avoid the compiler error. I think it should work to avoid the unnecessary () Should I submit a bugs ? As written on https://dlang.org/spec/function.html#property-functions: WARNING: The definition and usefulness of property functions is being reviewed, and the implementation is currently incomplete. Using property functions is not recommended until the definition is more certain and implementation more mature. So no, I don't think it's necessary to file a bug - we're aware they're somewhat wonky, and until a resolution has been agreed on, I don't think filing bugs on what's undecided behavior is worth it. -- Simen
Re: Idiomatic way to express errors without resorting to exceptions
On Saturday, 7 March 2020 at 15:44:38 UTC, Arine wrote: The case when there isn't a value should be handled explicitly, not implicitly. Propogating a None value isn't useful Except when it is useful, and shouldn't be handled explicitly. I have code in D, C and C++ that looks like this: ReturnValue result = someInitialValue; auto foo = getFoo(); if (!foo) return result; auto bar = foo.fun(); if (!bar) return result; return bar.gun(); In C#, this would be: return getFoo()?.fun().gun() ?? someInitialValue; And with implicit handling in Optional!T, it looks like this: return getFoo().oc.fun().gun().or(someInitialValue); Clearly the latter two are more readable, and I'm not gonna care that it's a little slower in the 99% of cases where speed is not important. -- Simen
Re: What does assigning void mean?
On Thursday, 5 March 2020 at 08:35:52 UTC, drug wrote: On 3/5/20 10:47 AM, mark wrote: In Adam Ruppe's D Cookbook there're these lines in a ref counting example: RefCountedObject o = void; // What does this mean/do? o.data = new Implementation(); o.data.refcount = 1; I don't understand the first line; could someone explain please? In D all vars are initialized by default. If you use assigning void then the var won't be initialized. To expand a bit on this: You probably don't want to initialize things with = void - it can lead to hard-to-track bugs and unexpected behavior. The reasons it's there is almost entirely as an optimization - if you know the variable will be initialized elsewhere void initialization ensure things won't be initialized twice when once is enough, and this can be faster. The other use case is when for whatever reason there is no valid default value, but you still want an instance. Probably in order to fill it with data from somewhere else. This would apply e.g. to structs with @disabled parameterless constructors whose contents you are reading from disk. In short, when you know you need to void initialize something, that's when you're ready to use it. Kinda like goto. -- Simen
Re: Call method if declared only
On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев wrote: Thanks all ! I happy ! Check this one: void On( T, M )( T o, M message ) { [snip] void main() { auto a = new A(); a.Send( a, WM_KEYUP ); a.Send( a, WM_KEYDOWN ); } That does mostly work, but fails for this code: void main() { Base a = new A(); a.send( a, WM_KEYUP ); } Basically, whenever you assign a derived to a base, this solution doesn't work, because T will be Base, not A. I enjoyed with the previous code, so I wrote the code necessary to handle any WM_ message: import core.sys.windows.windows; import std.stdio; import std.meta; template startsWith(string prefix) { enum startsWith(string s) = s.length >= prefix.length && s[0..prefix.length] == prefix; } enum getMessageValue(string s) = __traits(getMember, core.sys.windows.winuser, s); // Get the all the WM_ messages alias messageNames = Filter!(startsWith!"WM_", __traits(allMembers, core.sys.windows.winuser)); alias messageValues = NoDuplicates!(staticMap!(getMessageValue, messageNames)); class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { foreach (msg; messageValues) { case msg: if (auto that = cast(IMessageHandler!msg)this) { return that.handle(wParam, lParam); } break; } default: } return 0; } } interface IMessageHandler(alias msg) { mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);"); alias handle = mixin("On"~__traits(identifier, msg)); } class Button : Base, IMessageHandler!WM_KEYDOWN, IMessageHandler!WM_SETTINGCHANGE { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) { writeln("WM_SETTINGCHANGE"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); // None of these will print anything, as Base doesn't handle them b1.On(WM_KEYDOWN, 0, 0); b1.On(WM_SETTINGCHANGE, 0, 0); b1.On(WM_DRAWITEM, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); b2.On(WM_SETTINGCHANGE, 0, 0); // This will print nothing, as Button doesn't handle that message. b2.On(WM_DRAWITEM, 0, 0); } -- Simen
Re: Call method if declared only
On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote: Yes. Thank ! I read it. Problem is - OS has many messages + user messages... It mean what interfaces like IKeyDown must me declared. All. Dream on write less code... So let's create a template for that: interface IMessageHandler(alias msg) { mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);"); } And use it: import core.sys.windows.windows; import std.stdio; class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: if (auto that = cast(IMessageHandler!WM_KEYDOWN)this) { return that.OnWM_KEYDOWN(wParam, lParam); } break; default: } return 0; } } class Button : Base, IMessageHandler!WM_KEYDOWN { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); b1.On(WM_KEYDOWN, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); } You'll still have to specify for each derived class which messages they handle, but no need to define hundreds of interfaces separately. -- Simen
Re: Call method if declared only
On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote: Searching solution for idea ! For whatever reason, it seems my attempts at answering this earlier has disappeared into the void. Here: import core.sys.windows.windows; import std.stdio; class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: return tryCall!"OnWM_KEYDOWN"(wParam, lParam); default: } return 0; } auto tryCall(string name, Args...)(Args args) { import std.meta; alias This = typeof(this); alias module_ = __traits(parent, This); enum isSubclass(T...) = is(T[0] : This); alias getModuleMember(string name) = __traits(getMember, module_, name); enum hasMethod(T) = __traits(hasMember, T, name); // Get every member in this module enum memberNames = __traits(allMembers, module_); alias members = staticMap!(getModuleMember, memberNames); // Filter away anything that isn't derived from Base alias subclasses = Filter!(isSubclass, members); // Get rid of anything that doesn't have a method with the correct name alias subclassesWithMethod = Filter!(hasMethod, subclasses); // Sort them so you get the most derived types first alias Types = DerivedToFront!subclassesWithMethod; // Check for each type if the `this` is an instance of that specific one static foreach (T; Types) { if (cast(T)this !is null) { // And look up that method and call it. return __traits(getMember, cast(T)this, name)(args); } } // If `this` is not one of the types with that method, return some default value return 0; } } class Button : Base { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); b1.On(WM_KEYDOWN, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); } Now, this only works for subclasses defined in the same module. A possibly better solution would be interfaces: import core.sys.windows.windows; import std.stdio; class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: if (cast(IKeyDown)this) { return (cast(IKeyDown)this).OnWM_KEYDOWN(wParam, lParam); } default: } return 0; } } interface IKeyDown { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam); } class Button : Base, IKeyDown { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); b1.On(WM_KEYDOWN, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); } -- Simen
Re: Call method if declared only
On Friday, 28 February 2020 at 08:08:59 UTC, Виталий Фадеев wrote: On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote: Searching solution for idea ! Goal is to get System message, dispatch/route to method ! If method implemented only ! I dream on in future write clean code of a derived widgets like this : class Base { // dispatch void On( message ... ) { // call On() // example: call OnKeyUp() - if method OnKeyUp() is exists only } } May be other than derived ? May be templating ? How to implement ? Now I go in ths way: [snip] Searching for beauty readable code... Here's an attempt. It looks up all subclasses of Base in the same module, and calls the named method if it exists. However, it will fail for any subclass of Base that is defined in a different module. import core.sys.windows.windows; import std.stdio; class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: return tryCall!"OnWM_KEYDOWN"(wParam, lParam); default: } return 0; } auto tryCall(string name, Args...)(Args args) { import std.meta; alias This = typeof(this); alias module_ = __traits(parent, This); enum isSubclass(T...) = is(T[0] : This); alias getModuleMember(string name) = __traits(getMember, module_, name); enum hasMethod(T) = __traits(hasMember, T, name); // Get every member in this module enum memberNames = __traits(allMembers, module_); alias members = staticMap!(getModuleMember, memberNames); // Filter away anything that isn't derived from Base alias subclasses = Filter!(isSubclass, members); // Get rid of anything that doesn't have a method with the correct name alias subclassesWithMethod = Filter!(hasMethod, subclasses); // Sort them so you get the most derived types first alias Types = DerivedToFront!subclassesWithMethod; // Check for each type if the `this` is an instance of that specific one static foreach (T; Types) { if (cast(T)this !is null) { // And look up that method and call it. return __traits(getMember, cast(T)this, name)(args); } } // If `this` is not one of the types with that method, return some default value return 0; } } class Button : Base { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); b1.On(WM_KEYDOWN, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); } -- Simen
Re: How to copy const object?
On Thursday, 27 February 2020 at 11:28:11 UTC, Mitacha wrote: I've a const struct object and I'd like to make a mutable copy of it. Struct definition contains string and an array of structs. ``` struct A { string a; B[] b; } struct B { string a; string b; } ``` As far as I can tell copy constructor isn't generated for struct `A` because it contains an array. Correct? Is there an idiomatic way to create copy of a const object? As long as the copy is also const, you can just assign it to a new variable of the same type: const A a = A("foo",[B("bar", "baz")]); const A b = a; If, however, you require a mutable copy, things get a little more hair. In D, const is transitive, so that A.b[0] is a const(B). This will thus not work: A c = a; // Error: cannot implicitly convert expression a of type const(A) to A For built-in arrays, the .dup function does this: const int[] arr1 = [1]; int[] arr2 = arr1; // Fails to compile int[] arr3 = arr1.dup; // Works For symmetry, we can add a similar function to A: struct A { string a; B[] b; A dup() const { return A(a, b.dup); } } This lets us easily create a copy: A d = a.dup; Now, the reason you can't just assign from const(A) to A, while this works with const(B) to B, e.g., is that A contains mutable indirections. That is, you can change the contents of A.b. Since copies are generally shallow copies in D, allowing this behavior would have unfortunate consequences: const(A) a1 = A("foo", [B("bar", "baz")]); A a2 = a1; // Assume this worked assert(a1.b[0].a == "bar"); a1.b[0].a = "qux"; // Can't change b[0] through a1, since it's const a2.b[0].a = "qux"; // But we can change it through a2! assert(a1.b[0].a != "bar"); // And suddenly the const value in a1.b has changed. -- Simen
Re: String switch is odd using betterC
On Wednesday, 26 February 2020 at 08:32:50 UTC, Abby wrote: On Wednesday, 26 February 2020 at 08:25:00 UTC, Abby wrote: Any idea why? Ok so this is enough to produce the same result, it seems that there is a problem in string switch when there is more the 6 cases. extern(C) void main() { auto s = "F"; final switch(s) { case "A": break; case "B": break; case "C": break; case "D": break; case "E": break; case "F": break; case "G": break; } } The explanation can be found in druntime/import/core/internal/switch_.d: the __switch template does a simple binary search for less than 7 cases, but calls .idup on each case label for >= 7 cases. There's a comment there about why it's being done, but it seems to be a far more complicated fix than necessary - static immutable cases = [caseLabels]; works just as well, it seems. Anyway, the current code was added in this commit: https://github.com/dlang/druntime/commit/fa665f6618af7dbc09ed5ba1333f385017b7ece8. Anyways, reported here: https://issues.dlang.org/show_bug.cgi?id=20613 -- Simen
Re: Alternative to friend functions?
On Tuesday, 18 February 2020 at 12:43:22 UTC, Adnan wrote: class Wife(uint N) : Female { FemaleID engagedTo = -1; const MaleID[N] preferences; this(MaleID[N] preferences) { this.preferences = preferences; } } void engage(N)(ref Wife!N, wife, ref Husband!N husband) { // Here, I want to access both husband and wife's engaged_to } Petar's answer covers your question, so I won't elaborate on that, but I'd like to point out that as Wife and Husband are classes, you probably don't intend to take them by ref - classes are always by ref in D, so you're effectively passing a reference to a reference to a class in `engage`. Basically: class Foo { int n; } void fun(Foo f) { f.n = 3; // Local copy of the reference - does not modify other references. f = null; } void gun(ref Foo f) { f = null; } unittest { Foo f = new Foo(); Foo g = f; f.n = 17; // f and g point to the same object: assert(f.n == 17); assert(g.n == 17); fun(f); // fun() changed the object that both f and g point to: assert(f.n == 3); assert(g.n == 3); gun(f); // gun() changed f to no longer point at the same object, but left g untouched: assert(f is null); assert(g !is null); assert(g.n == 3); } -- Simen
Re: How to declare a virtual member (not a function) in a class
On Tuesday, 18 February 2020 at 12:37:45 UTC, Adnan wrote: I have a base class that has a couple of constant member variables. These variables are abstract, they will only get defined when the derived class gets constructed. class Person { const string name; const int id; } class Male : Person { this(string name = "Unnamed Male") { static int nextID = 0; this.id = nextID++; this.name = name; } } The compiler restricts me from assigning those two functions. How can I get around this? const members can only be set in the constructor of the type that defines them. To set them in a subclass, forward the values to the superclass' constructor: class Person { const string name; const int id; protected this(string _name, int _id) { id = _id; name = _name; } } class Male : Person { this(string name = "Unnamed Male") { static int nextID = 0; super(name, nextID++); } } -- Simen
Re: Why can't I pass a const array to a function that takes scope const arrays?
On Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote: cdsa ~master: building configuration "cdsa-test-library"... source/strassens_matmul.d(22,16): Error: cannot implicitly convert expression [row][column] of type const(uint)* to uint* source/strassens_matmul.d(37,36): Error: template instance strassens_matmul.getPointPtr!uint error instantiating source/strassens_matmul.d(48,29): I'd just finished writing a long post explaining the stuff you've apparently figured out. Ah well. :p In this case, getPointPtr return T*, but takes scope const ref T[][]. Since getPointPtr always takes a mutable array, you could just get rid of const on its parameters. Alternatively, if you want to be able to use it on arrays of different constness, you could use inout: inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t column) { This will return a pointer to a mutable T if that's what the array holds when you call the function, const(T) if it's a const array, immutable(T) if it's immutable, and so on. The same can be done with the other functions you have. You are also somewhat overusing const, scope and ref, I'd say - you should not take an array by ref unless you plan on modifying it, which you are not doing in getPointPtr or any other of your functions. scope may be worth it, as it guarantees you won't be sending the data elsewhere. None of these are necessary on your ulongs, which are passed by value and never attempted modified. If you really like the extra guarantee that you don't accidentally modify them, feel free to keep 'const', but 'scope' on a ulong does nothing, and it's been argued it should be a compiler error. Lastly, you're using ulongs a lot, and this is mostly correct when compiling for 64-bit, but makes code fail to compile for 32-bit. Using size_t instead makes for code that works for both. All in all, I end up with this code: module strassens_matmul; debug { static import std; } package { size_t getRowSize(T)(const T[][] mat) { return mat[0].length; } size_t getColumnSize(T)(const T[][] mat) { return mat.length; } T[][] createMatrix(T)(size_t rowSize, size_t columnSize) { return new T[][](rowSize, columnSize); } /// row and column are 0 index-based inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t column) { return [row][column]; } T getPointCopy(T)(const T[][] mat, size_t row, size_t column) { return mat[row][column]; } T[][] mulIterative(T)(const T[][] mat1, const T[][] mat2) { auto result = createMatrix!T(getRowSize!T(mat1), getColumnSize!T(mat2)); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } } unittest { const uint[][] matA = [[10, 20, 10], [4, 5, 6], [2, 3, 5]]; const uint[][] matB = [[3, 2, 4], [3, 3, 9], [4, 4, 2]]; const uint[][] matC = [[130, 120, 240], [51, 47, 73], [35, 33, 45]]; assert(matA.mulIterative(matB) == matC); } -- Simen
Re: operator overload for sh-like scripting ?
On Monday, 17 February 2020 at 13:03:38 UTC, Basile B. wrote: eg Sh(echo) < "meh"; struct Sh { // you see the idea we have op overload for < here } You can't overload < separately - all the comparison operators (<, <=, >, >=) are handled via opCmp. Even if you choose to go down that route, there are other issues - opCmp needs to return something that may be compared to 0, since (a < b) is rewritten as (a.opCmp(b) < 0), and the compiler checks if you are simply discarding the return value of a comparison, so all in all, you shouldn't do that in D (and the hoops you have to jump through to make it work makes the code a lot less readable): struct Sh { int opCmp(string s) { import std.stdio : writeln; writeln(s); return 0; } } unittest { Sh sh; auto _ = sh < "baz"; } This is also not chainable, so something like (sh < "foo" < "bar") won't work, even with parentheses. There's also the issue of (a < b) having a defined meaning in D (a less than b), and such overloading leads to code that may be less readable. This is a point with differing opinions, and I'm not firmly on either side of that argument, but it's worth pointing out. Now, if you absolutely want something that's somewhat similar in regular D code, there's <<: struct Sh { Sh opBinary(string op : "<<")(string s) { import std.stdio : writeln; writeln(s); return this; } } unittest { Sh sh; sh << "foo" << "bar"; } While this works, it's a design choice that C++ has gotten a lot of flak for, including one of my favorite C++ quotes: "I saw 'cout' being shifted 'Hello world' times to the left and stopped right there." There are cases where it's not at obvious to the reader of the code what's happening, so such operator overloading should be used with caution. A better choice, perhaps, if using < is important, would be to use a DSL and have it obvious in the code that normal D rules aren't at play: void fun() { Sh sh; mixin dsl!` sh < "foo"; `; } At this point though, you're looking at a considerable chunk of code just for a bit of syntactic sugar. -- Simen
Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature wrote: Here you go: import std; // extract the types that make up the tuple auto transposeTuple(T : Tuple!Types[], Types...)(T tuples) { // templated function that extracts the ith field of an array of tuples as an array auto extractArray(int i)() { return tuples.map!(a => a[i]).array; } // return tuple of calls to extractArray, one for each tuple index return tuple(staticMap!(extractArray, aliasSeqOf!(Types.length.iota))); } void main() { Tuple!(int, double)[] array; array ~= tuple(1, 2.0); array ~= tuple(3, 4.0); Tuple!(int[], double[]) tuple = array.transposeTuple; assert(tuple[0] == [1, 3]); assert(tuple[1] == [2.0, 4.0]); } One tiny thing: the above fails for tuples with named fields, like Tuple!(int, "a", string "b"). This code handles that case, and preserves field names: import std.meta : staticMap, aliasSeqOf; import std.typecons : Tuple; import std.range : array, iota; import std.algorithm : map; alias ToArray(T) = T[]; alias ToArray(T...) = T; alias ToArrayTuple(T : Tuple!U, U...) = Tuple!(staticMap!(ToArray, U)); auto transpose(T : Tuple!U, U...)(T[] arr) { auto extract(int i)() { return arr.map!(a => a[i]).array; } return ToArrayTuple!T(staticMap!(extract, aliasSeqOf!(T.Types.length.iota))); } unittest { alias T = Tuple!(int, "a", string, "b"); auto a = [T(1, "a"), T(2, "b")]; assert(a.transpose.a == [1, 2]); assert(a.transpose.b == ["a", "b"]); } -- Simen
Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])
On Monday, 17 February 2020 at 11:51:52 UTC, FeepingCreature wrote: On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote: Hi all, There's something in Phobos for that? Thank you Here you go: import std; // extract the types that make up the tuple auto transposeTuple(T : Tuple!Types[], Types...)(T tuples) { // templated function that extracts the ith field of an array of tuples as an array auto extractArray(int i)() { return tuples.map!(a => a[i]).array; } // return tuple of calls to extractArray, one for each tuple index return tuple(staticMap!(extractArray, aliasSeqOf!(Types.length.iota))); } void main() { Tuple!(int, double)[] array; array ~= tuple(1, 2.0); array ~= tuple(3, 4.0); Tuple!(int[], double[]) tuple = array.transposeTuple; assert(tuple[0] == [1, 3]); assert(tuple[1] == [2.0, 4.0]); } ^^ Do what he said - I misread the title. :) -- Simen
Re: From [Tuple!(A,B), ...] to Tuple!(A[], B[])
On Monday, 17 February 2020 at 11:07:33 UTC, foozzer wrote: Hi all, There's something in Phobos for that? Thank you import std.meta : staticMap; import std.typecons : Tuple; // Turn types into arrays alias ToArray(T) = T[]; // Leave everything else the same alias ToArray(T...) = T; // Now apply the above to each element of the Tuple template args: alias ToArrayTuple(T : Tuple!U, U...) = Tuple!(staticMap!(ToArray, U)); unittest { alias A = Tuple!(int, string); assert(is(ToArrayTuple!A == Tuple!(int[], string[]))); alias B = Tuple!(int, "a", string, "b"); assert(is(ToArrayTuple!B == Tuple!(int[], "a", string[], "b"))); } -- Simen
Re: Global version/debug statements in file?
On Wednesday, 12 February 2020 at 08:44:24 UTC, cc wrote: Is there some way to globally declare version= or debug= statements in a file and have them apply to the entire project being compiled? As the documentation says these only apply to the module scope they exist in, and need to be added to the command line otherwise. It would be a bit easier for me to maintain a separate .d source file when I want to add/comment out statements for testing than to keep updating the build command line. https://dlang.org/dmd-windows.html#switches specifies that DMD may be passed a file on the command line that contains compiler arguments and switches. This may be freely combined with regular command line arguments if you so wish. So, you could have a file called 'versions' containing this: # Setting 'Compress' version -version=Compress # Optionally set other versions #-version=Foo #-version=Bar and feed it to dmd like so: dmd -w -wi -g @versions -main foo.d -- Simen
Re: Custom separator in array format
On Tuesday, 28 January 2020 at 07:36:25 UTC, Malte wrote: I want to format an array using the %(...%) syntax. How can I change the separator? I tried to use ? and add it as additional parameter, but that doesn't seem to work on arrays: import std; void main() { writeln("This works:"); writefln("%,2?d", '_', 2000); // 20_00 auto vec = [1000, 2000, 3000]; writeln("This should fail (separator character expected) but the ? is just ignored:"); writefln("%(%,2?d\t%)", vec); // 10,0020,00 30,00 writeln("This throws:"); writefln("%(%,2?d\t%)", '_', vec); // std.format.FormatException@/dlang/dmd/linux/bin64/../../src/phobos/std/format.d(2271): incompatible format character for integral argument: %( } I think I see why it's not working. Essentially, for each element of vec, format is called with only that element as an argument. Essentially, rather than: foreach (e; vec) writef("%,2?d\t", '_', e); writeln(); You get: foreach (e; vec) writef("%,2?d\t", e); writeln(); For whatever reason, it doesn't throw when missing an argument for the separator - I'd say this is a bug (https://issues.dlang.org/show_bug.cgi?id=20541). For now, you can work around the issue this way: import std.stdio : writefln; import std.format : format; import std.algorithm : map; auto vec = [1000, 2000, 3000]; writefln("%-(%s\t%)", vec.map!(e => format!"%,2?d"('_', e))); -- Simen
Re: @disable("reason")
On Wednesday, 8 January 2020 at 07:03:26 UTC, Jonathan M Davis wrote: you could just document that no one should ever use its init value explicitly, and that they will have bugs if they do You also create a static init member marked @disable: struct S { @disable this(); @disable static S init(); } This will give sensible error messages anywhere .init is being used. Now, Phobos and other libraries might expect that .init is always working, so this could potentially be a problem.
Re: @disable("reason")
On Wednesday, 8 January 2020 at 08:26:51 UTC, user1234 wrote: class Example { @disable this() { pragma(msg, "not allowed..."); } } void main() { new Example(); } outputs: not allowed... /tmp/temp_7F8C65489550.d(12,5): Error: constructor `runnable.Example.this` cannot be used because it is annotated with `@disable` However, it will print that message even if the constructor is never called. If you make the constructor a template instead, you will only get the message when someone attempts to use the default constructor: class Example { @disable this()() { pragma(msg, "not allowed..."); } } void main() { new Example(); } Sadly, this does not work for structs, as they don't really have a default constructor, as Jonathan pointed out. -- Simen
Re: Should I stop being interested in D language if I don't like to see template instantiation in my code?
On Thursday, 14 November 2019 at 09:30:23 UTC, user9876 wrote: A good thing is that in many cases the template instance parameters can be deduced from the arguments used: --- import std; void main() { assert(max(0,1) == 1); // same as assert(max!(int,int)(0,1) == 1); } --- This feature is known as "IFTI" see §6, https://dlang.org/spec/template.html#function-templates. You're not forced to use the D templates but you'll have to write many code by yourself because the standard library use them everywhere. IFTI is nifty. (sorry, I had to) -- Simen