Re: Mixin template overloads not working
On Tuesday, 7 December 2021 at 12:43:40 UTC, Rumbu wrote: Bug or feature? Feature. It even has a name: "overload set". It keeps you from accidentally calling a function you had no idea existed, for example because of a name clash. Is there any workaround? Yes, the error message is very clear.
Re: Should this always work?
On Saturday, 1 May 2021 at 06:17:36 UTC, Mike Parker wrote: On Saturday, 1 May 2021 at 04:55:10 UTC, frame wrote: I always thought as long as an object implements an interface, it should be able to cast it from a void* if it really points to a supporting object. No. An interface is like a pointer to a pointer. Can you elaborate on this one? I don't really get it. Is an object handle also like a pointer to a pointer? (I feel like I can learn something here.)
Re: Is there a more elegant way to do this in D?
On Thursday, 8 April 2021 at 18:06:25 UTC, Meta wrote: On Thursday, 8 April 2021 at 18:01:56 UTC, Meta wrote: On Thursday, 8 April 2021 at 12:19:29 UTC, WebFreak001 wrote: ```d string to01String(int[] x) @safe { auto conv = x.to!(ubyte[]); // allocates new array, so later cast to string is OK conv[] += '0'; // assume all numbers are 0-9, then this gives the correct result return (() @trusted => cast(string)conv)(); } ``` The @trusted lambda can also be replaced with [std.exception.assumeUnique](https://dlang.org/library/std/exception/assume_unique.html). Never mind me, assumeUnique is @system (or at least it's inferred as @system), and anyway, you can't implicitly convert `immutable(ubyte)[]` to `immutable(char)[]`. It has to be. It's not `@safe` quite obviously.
Re: Manually check struct invariants
On Tuesday, 23 March 2021 at 23:27:54 UTC, Paul Backus wrote: On Tuesday, 23 March 2021 at 22:22:12 UTC, Q. Schroll wrote: For a class object obj, one can use assert(obj) to get its invariants checked. How to do this for structs? https://dlang.org/spec/expression.html#assert_expressions If the first AssignExpression is a pointer to a struct instance for which a Struct Invariant exists, the Struct Invariant must hold. So, you would write `assert(&obj)` for a struct instance. I searched for it, but while for some reason, my brain read "If the first AssignExpression is a reference to a class instance for which a Class Invariant exists, the Class Invariant must hold." it failed to do so for the next sentence. Thank you.
Manually check struct invariants
For a class object obj, one can use assert(obj) to get its invariants checked. How to do this for structs?
Compiler version "dirty"
When I enter `dmd --version`, it says: DMD64 D Compiler v2.095.1-dirty What should the "dirty" mean? To me, it seems looks something went wrong somewhere.
Re: Why are multiple instances of the single enum created?
On Monday, 1 February 2021 at 11:39:26 UTC, Per Nordlöw wrote: On Monday, 1 February 2021 at 11:37:49 UTC, Per Nordlöw wrote: Ok, so then my follow-up question becomes, does the right hand sides of these two assignment share the same AST node? If not, why? Because such a shared AST node could be potentially mutated in different ways in different contexts during its passes? The spec says nothing about AST nodes. You can ask what DMD does (I don't know), but technically speaking, ASTs are an implementation detail of a compiler. A compiler need not have ASTs at all to follow the spec (unless the spec demands ASTs to exist, which I think it does not do). A compiler can change its AST nodes to a different yet equivalent representation without issue (unless the spec demands ASTs to exist and be of a certain form, which I think it does not do).
Re: Why are multiple instances of the single enum created?
On Monday, 1 February 2021 at 20:00:26 UTC, Q. Schroll wrote: On Monday, 1 February 2021 at 09:40:20 UTC, Per Nordlöw wrote: An enum only exists at compile-time, and does not occupy any space. Each time it's referenced, a new instance of the value is created. Why is that? Short answer: An enum is a literal you can refer to by name. That's my mind-model for an enum. I forgot to mention: An enum can have a precise type. As a stupid example, there are no first-class literals of type short or byte. But you can easily have short or byte enums. Also, the empty slice [] is typed void[] if you ask typeof([]); but an empty enum can be typed as any T[].
Re: Why are multiple instances of the single enum created?
On Monday, 1 February 2021 at 09:40:20 UTC, Per Nordlöw wrote: An enum only exists at compile-time, and does not occupy any space. Each time it's referenced, a new instance of the value is created. Why is that? Short answer: An enum is a literal you can refer to by name. That's my mind-model for an enum. Long answer: If you use the literal "abc" twice, because it's underlying type is immutable (string == immutable(char)[]), the compiler can elide multiple allocations. But ['a','b','c'] has to be allocated each use. Basically, it lowers to a `new char[](3)` plus initialization. It is completely irrelevant how the value has been determined.
Re: How to covert dchar and wchar to string?
On Monday, 25 January 2021 at 18:45:11 UTC, Rempas wrote: Actually what the title says. For example I have dchar c = '\u03B3'; and I want to make it into string. I don't want to use "to!string(c);". Any help? char[] dcharToChars(char[] buffer, dchar value) { import std.range : put; auto backup = buffer; put(buffer, value); return backup[0 .. $ - buffer.length]; } void main() { dchar c = '\u03B3'; char[4] buffer; char[] protoString = dcharToChars(buffer, c); import std.stdio; writeln("'", protoString, "'"); } Unfortunately, `put` is not @nogc in this case.
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Unless you have a good reason, use a slice and not a static array: double[] result; The result of std.array.array will be a slice anyway.
Re: How can I use UFCS for a loop
On Tuesday, 26 January 2021 at 00:47:09 UTC, Tim wrote: Hi all, How can I change the following to a more D-like approach by using UFCS? double[3] result; Json json = res.readJson; for(int i = 0; i < json.length; i++){ result[i] = json[i].to!double; } I'd prefer to do something like: result = res.readJson[].map!(to!double); Use std.array.array (alias: std.range.array) to make the range returned my map!(to!double) into an array. Note that the result of map isn't actually evaluated until it is iterated. std.array.array will iterate and collect. https://dlang.org/phobos/std_array.html#array result = res.readJson[].map!(to!double).array; should work perfectly.
Re: How do I overload += operator?
On Monday, 25 January 2021 at 21:53:15 UTC, Jack wrote: That naming is confusing op: it is an operator method Op: it takes an operator as a parameter Assign: kinda obvious. As an example, there are opIndex, opIndexAssign and opIndexOpAssign. opIndex overloads obj[i]. opIndexAssign overloads obj[i] = rhs, and opIndexOpAssign overloads opj[i] += rhs. Maybe, in the greater scheme, the naming makes more sense to you.
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 18:44:53 UTC, Jonathan Levi wrote: On Tuesday, 12 January 2021 at 17:46:14 UTC, Q. Schroll wrote: It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me. I like the variadic feature for classes, but I wish it worked for structs as well, given that structs are value types on the stack anyway, the same assembly could have either signature (assuming matching argument/struct ordering). But why does this compile? ``` struct S {/*...*/} void fun(S s...) {/*...*/} ``` If structs do not work as variadic parameters, why does `fun` still compile? Because D does allow you to specify things that have no effect. People sometimes complain about this as nonsense, but it has its merits in meta-programming: void fun(T)(T t...) { } Here, if T is a class or array type (including static arrays, btw), the dots have an effect, otherwise not. It would be unnecessary to require a split on the basis what T is.
Re: properly passing strings to functions? (C++ vs D)
On Monday, 11 January 2021 at 16:53:50 UTC, IGotD- wrote: I usually use "const string text" because D has no implicit declaration of variables. So using "ref" will not create a variable. This is contrary to C++ where passing as "const std::string &text" has a performance benefit and also C++ creates a unnamed variable for you. Did you consider `in`? It will do that in some time and do it now with -preview=in. If you're using `const`, in almost all cases, `in` will work, too, and be better (and shorter).
Re: properly passing strings to functions? (C++ vs D)
On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote: A beginner question: How to pass strings properly to functions in D? Is there any allocation going on if just use a function as "myPrint"? In C++ I have often seen calls where one just passes a reference/const reference to a string to avoid allocation. C++: void myPrintCPP(const std::string& input){ ... } D: void myPrint(string text){ ... } void myPrintRef(ref string text) { ... } In D, `string` is an abbreviation for the type immutable(char)[], i.e. slice of immutable char. The slice type is a pointer+length pair, a (T*, size_t) tuple, it is very lightweight. Using `ref T[]` (that includes `ref string` aka `ref immutable(char)[]` is the way if you want reassignments or expanding/shrinking of the array to be visible to the caller. Since the cost of copying a pointer and a length is very low, I'd just use this: void myPrint(string text) { ... } It'll be probably what you want. Since you cannot write the immutable characters, if you don't intend to reassign, expand, or shrink the string locally, you can use `in string text`. You can basically only read `in` parameters for information. What `in` buys you is that the compiler will figure out the best way to pass the object. C++'s const T& will reference always, which is worse than a copy for small types. D's `in` will copy if the compiler thinks it's cheaper than referencing. Give https://dlang.org/changelog/2.094.0.html#preview-in a read, if you want details about `in`. Use it when it applies. It also documents intent.
Re: Variadic Struct Parameter
On Tuesday, 12 January 2021 at 17:26:15 UTC, Jonathan Levi wrote: Why is this not working? ``` struct S { int x; string y; } void fun(S s ...) { This is intended for arrays and classes, not structs. Using ... for something other than arrays and c fun(S(5,"hi")); That one should compile... fun(5,"hi"); and the second one not. It's obvious why arrays work, it's the primary use case. I have no idea why classes are allowed. That classes are allowed, but structs are not, makes no sense to me.
Re: [Understanding] Classes and delegate inheritance vs function pointers
On Saturday, 9 January 2021 at 21:57:43 UTC, sighoya wrote: On Saturday, 9 January 2021 at 20:20:38 UTC, Q. Schroll wrote: That's not what I mean. You copy the reference. That's not what referencing meant. Derived d = new Derived(); Base* bp = &d; // fails const(Base) cbp = &d; // compiles. Generally, allowing covariant assignment for the Ptr, i.e. T*, type only in case of const T* strikes me. IMHO, both should be synchronously (dis)allowed. I'm unsure what you mean. If you have an array `cars` of type Car[], you can treat it as a const(Vehicle)[] because reading a Car as a Vehicle is unproblematic. But if it could bind to Vehicle[], its elements could be written arbitrary Vehicles. Say it worked, then: Car[] cars = ...; Vehicle[] vehicles = cars; vehicles[0] = new Boat; // err... // cars[0] is a Boat now!? Now what? Do what Java does and throw an Exception? Or use const to prevent mutation? Because D doesn't support co(ntra)variance, it should be both disallowed? Imagine for a moment, `const` were named `read_only` and there were a specifier `write_only`. That looks silly, but makes sense in some cases: Vehicle[] vehicles = ...; write_only(Car)[] cars = vehicles; // WTF!? cars[i] = new Car; // wait, that's actually okay... Because write_only isn't a thing in D, contravariance is an odd thing to get your a D mind around. Otherwise, because D already support the const case, why not the non const case? The non-const case makes no sense. Are there any alignment issues supporting the non const case? It's not alignment, probably. (Maybe it is, I know almost nothing about alignment, to be honest.) Among other things, in the non-const case, as you call it, the type system cannot guarantee anymore that stuff that is typed some way actually contains those objects. It is one of the major issues Java has and why everyone and their mom tells you not to use Java's arrays and instead use List or similar well-behaved constructs. BTW, my question wasn't about classes at all. I used them as an illustration what works and asked why (seemingly) the same thing doesn't with function pointers.
Re: [Understanding] Classes and delegate inheritance vs function pointers
On Saturday, 9 January 2021 at 20:00:35 UTC, Jacob Carlborg wrote: On 2021-01-09 19:16, Q. Schroll wrote: Say I have a class hierarchy like this: class Base { } class Derived : Base { } A Derived object cannot be referenced as a Base object, but as a const(Base) object. That makes sense to me. It can: Base b = new Derived(); That's not what I mean. You copy the reference. That's not what referencing meant. Derived d = new Derived(); Base* bp = &d; // fails const(Base) cbp = &d; // compiles. Is there a reason all you're examples are using pointers? Yes. Actually, I need it for slices, but only pointer part of it really mattered. A Derived[] is implicitly a const(Base)[], not a Base[]. A void delegate() @safe[] is implicitly a const(void delegate())[]. But it seems a void function() @safe[] **isn't** implicitly a const(void function())[]. Functions taking those are kind of useless like that.
[Understanding] Classes and delegate inheritance vs function pointers
Say I have a class hierarchy like this: class Base { } class Derived : Base { } A Derived object cannot be referenced as a Base object, but as a const(Base) object. That makes sense to me. One can replace Base by a @system delegate type (SysDG) and Derived by a @safe delegate type (SafeDG) and it works the same way: a SafeDG object cannot be referenced as a SysDG object, but as a const(SysDG) object. However, if I try that with function pointers instead of delegates (SysFP, SafeFP), for some reason, a SafeFP cannot be referenced as a const(SysFP). This makes no sense in my head. Is there some reason I'm unable to see? Example code is here: https://run.dlang.io/is/zSNArx
Re: Alias woes
On Saturday, 12 December 2020 at 01:02:56 UTC, SealabJaster wrote: Please see this shortened snippet: https://godbolt.org/z/j8f3x5 I've ran into annoyances before when using aliases to member fields, but something subtle like this was rather annoying to figure out. Why does the compiler feel the need to embed a context pointer anytime you provide an to alias a member? In my case the function was also writing seemingly garbage values into the .ptr and .length fields for the ref'd string, but it doesn't seem to happen in the godbolt snippet. Bonus, a pet peeve of mine: https://godbolt.org/z/bnK91f I don't have an answer, but aliasing non-static fields outside the struct isn't something one does often. This is probably a bug.
Re: Avoid deallocate empty arrays?
On Thursday, 17 December 2020 at 16:11:37 UTC, IGotD- wrote: It's common using arrays for buffering Outside of CTFE, use an Appender.¹ Unless you're having a const/immutable element type, Appender can shrink and reuse space.² If you have, reallocation is necessary anyway not to break const/immutable' guarantees. ¹ https://dlang.org/phobos/std_array.html#appender ² https://dlang.org/phobos/std_array.html#.Appender.clear
Re: UFCS functions with both pointers and refs
On Tuesday, 15 December 2020 at 20:38:04 UTC, Dave P. wrote: The use case would be to define extension methods on a struct outside of where the struct is defined. The extension method mutates the state of the struct, so I want to ensure I am modifying the original struct and not a copy. If it’s a method and I call it on a pointer to the struct, the pointer will get auto-dereferenced and everything is great. So my question is that if I want an extension method as a free function, do I have to write both the version whose first argument is a pointer to the struct and the version whose first argument is a ref, or is there some keyword or other technique so that the pointer gets auto-dereferenced the same way as if it were a method. It sounds like the answer is no and I have to write a version that just dereferences the pointer and calls the ref version. Now it's coming together. The easiest way to do this is using an overload taking a `ref` (non-pointer) value and another taking a pointer (by copy, I guess). R f(ref T value, Ts args) { /* doing the actual work */ } R f(T* ptr, Ts args) { f(*p, args); } // manually dereference You cannot get around doing the actual `f`, and the addition isn't that big. I think that's the best solution unless you have to deal with non-copyable types among Ts. Then you need to forward those properly. I couldn't really do better using one template instead of this simple overload. (Certainly a template can be made, but it is clearly not the better solution.)
Re: closures + struct: Error: forward reference to inferred return type of function call
On Monday, 14 December 2020 at 14:39:14 UTC, ddcovery wrote: On Monday, 14 December 2020 at 12:22:26 UTC, ddcovery wrote: int opCmp(Number other){ return _value - other.value; }; Correction: bool opEquals(Number other){ return _value == other.value; }; You could just give the struct a variable and use that instead of the enclosing function's parameter: https://run.dlang.io/is/4Lqf15 Then, the struct can actually be static.
Re: UFCS functions with both pointers and refs
On Sunday, 13 December 2020 at 19:02:34 UTC, Dave P. wrote: On Sunday, 13 December 2020 at 18:44:20 UTC, Mike Parker wrote: On Sunday, 13 December 2020 at 18:31:54 UTC, Dave P. wrote: Do I have to write both and have one forward to the other for more complicated functions? For free functions, yes. Is there any way to write the function as a template that is generic over a parameter being a pointer or a reference, but does not allow passing a copy? I'm not sure what you mean by a reference. D doesn't have references in general, only class references that are just glorified pointers. There are also `ref` parameters, but those aren't generally referred to as "references" and are inside the function almost indiscernible from non-ref parameters. So, I'll ignore that. Copying only takes place under one circumstance: When an lvalue is passed to a function that does not take that argument by `ref`. So one possibility is to just define that overload and @disable it. You don't even need a template for this: void f(X x); // matches lvalues and rvalues void f(ref X x); // matches lvalues only The latter is a better match than the former for lvalues. @disable'ing it will do the job. On the other hand, not @disable'ing it will make `f` work with any argument by moving rvalues to the former overload and referencing lvalues using the second one. On templates, those can be unified by slapping `auto ref` before the parameter. You can also use `auto ref` (which infers `ref` from the passed argument) and check it with an `if` template constraint: void f(T)(auto ref T arg) if (!__tratis(isRef, arg)) // only accepts non-ref args { /* your code here */ } The constraint can easily be flipped.
Re: Why can I call a function with mismatched parameter type?
On Friday, 11 December 2020 at 11:32:09 UTC, rikki cattermole wrote: string is not a built in type. It is an alias defined by druntime. https://github.com/dlang/druntime/blob/master/src/object.d#L35 int on the other hand is defined by the compiler. It understands it. It doesn't magically understand it. `int` is a keyword and thus not a legal identifier. From a grammar perspective, in `(x, y) { }`, x and y are parsed as types. [1] However, in lambda expressions, when there's a type only and no parameter (according to the grammar) given, the compiler treats a single identifier as a parameter with inferred type. Since `int` is not an identifier, but a keyword, that treatment does not happen. As you explained correctly, `string` is merely an identifier and thus seen as a parameter name. [1] https://dlang.org/spec/grammar.html#Parameters
Re: Pass enum variable as const ref arg
On Friday, 4 December 2020 at 12:54:25 UTC, Andrey wrote: [...] WTF? If you come from a C or C++ background, it's quite reasonable to think of enum stuff like a #define macro. You're using static arrays, but note that array literals allocate in many use cases. It really is like a C/C++ macro. Use n times = allocate n times. You avoid that with a static immutable completely. That said, if you use the value of that enum only at compile-time, there's no need for a static immutable. Hope that this rule of thumb sheds some more light on how to achieve certain stuff.
Re: Anybody know if I can build DMD with Visual Studio 2019?
On Friday, 4 December 2020 at 09:32:29 UTC, Imperatorn wrote: On Wednesday, 2 December 2020 at 22:37:06 UTC, WhatMeWorry wrote: It works now. Not sure what I did to _not_ make it work yesterday. That's easy. You made a post here about it and the universe got scared. This made my day.
Re: How to unit-test a phobos module?
On Thursday, 26 November 2020 at 05:29:16 UTC, Mike Parker wrote: On Wednesday, 25 November 2020 at 21:36:36 UTC, Q. Schroll wrote: [1] https://wiki.dlang.org/Building_under_Windows You might try Digger. That will hide all the tedious bits. https://code.dlang.org/packages/digger I think using digger in principle works and I assume the problems I got aren't Digger's fault, but ae's. Building DMD + DRuntime failed. In my working folder (created by DUB running Digger), there's DMD.exe, but trying compiling anything results in "Error: cannot find source code for runtime library file 'object.d'" I did nothing but follow the instructions on code.dlang.org/packages/digger : dub fetch digger dub run digger -- build I tried building the current version v2.94.2 and tried --model=64, nothing helped. The error I'm presented is when work\build\bin\dmd.exe -lib -ofphobos64.lib -Xfphobos.json -conf= -m64 [..1] -I../druntime\import std\stdio.d [..2] is executed. [..1] IMO unrelated options [..2] following many more std modules, probably all that there are (haven't checked) The error message is: std\stdio.d(16): Error: module stddef is in file 'core\stdc\stddef.d' which cannot be read I have no idea why the import failed. The stdc subfolder isn't in the core folder, but that core folder isn't even in a druntime/import folder anyway. Something's going horribly wrong. It seems something beyond us just doesn't want me to get D stuff done. :( Tomorrow, I'll try setting up a dual boot and give it a shot there. (Not the dub experience but following https://wiki.dlang.org/Building_under_Posix) Thank you all for your answers.
Re: How to unit-test a phobos module?
On Wednesday, 25 November 2020 at 21:57:12 UTC, H. S. Teoh wrote: On Wed, Nov 25, 2020 at 09:49:12PM +, Paul Backus via Digitalmars-d-learn wrote: On Wednesday, 25 November 2020 at 21:16:06 UTC, Q. Schroll wrote: > On Wednesday, 25 November 2020 at 21:11:24 UTC, Paul Backus > wrote: > > On Wednesday, 25 November 2020 at 20:58:20 UTC, Q. Schroll > > wrote: > > > My setup: > > > * A fresh DMD installed a few minutes ago. > > > * Clone of my Phobos fork with up-to-date changes from > > > dlang/phobos/master. > > > > Do you have clones of dmd and druntime too? > > Why would I need those? I haven't needed them back then. copyEmplace isn't in druntime 2.094.2. My guess is that the problem is caused by trying to compile Phobos with a compiler that uses an incompatible version of druntime. One of the issues is, I don't know what DRuntime really is. As far as I understand on the surface-level, it's functionality one would expect to be implemented by the compiler, but actually implemented in plain D code. A low-level Phobos if you want. So I'm a little confused why there's even a need for it to be "built". Isn't it "just code" like Phobos? I'm increasingly frustrated because, honestly, it seems I don't know enough about the build processes or build tools used. The Wiki expects Digital Mars make to be there, also says explicitly not to confuse it with GNU make, but in my DMD folder there is none. Since it's a plain install, I suspect the Wiki is outdated. How am I expected to figure things out? It seems like everyone else knows how to do it, just I'm too stupid. *ME* Why would I need those? I haven't needed them back then. I wrote that not saying "do the work for me, guys" but "please tell me what changed".
Re: How to unit-test a phobos module?
On Wednesday, 25 November 2020 at 21:16:15 UTC, Steven Schveighoffer wrote: I typically do: make -f posix.mak std/.test -Steve For some reason, [1] says `make.exe` would be installed by the DMD installer, but I found none. It explicitly says not to use GNU make. (I'm on Windows.) [1] https://wiki.dlang.org/Building_under_Windows
Re: How to unit-test a phobos module?
On Wednesday, 25 November 2020 at 21:11:24 UTC, Paul Backus wrote: On Wednesday, 25 November 2020 at 20:58:20 UTC, Q. Schroll wrote: My setup: * A fresh DMD installed a few minutes ago. * Clone of my Phobos fork with up-to-date changes from dlang/phobos/master. Do you have clones of dmd and druntime too? Why would I need those? I haven't needed them back then.
How to unit-test a phobos module?
When trying to unit-test an unchanged phobos module from phobos/master, I get errors such as module core.lifetime import copyEmplace not found and template instantiation errors. What is the correct arguments to pass to (r)dmd? I know it worked for me some years ago, but somehow, it doesn't work now. I've looked at [1], [2], [3] which didn't work (maybe outdated?). How do you do it and what am I doing wrong? My setup: * A fresh DMD installed a few minutes ago. * Clone of my Phobos fork with up-to-date changes from dlang/phobos/master. In the clone's folder, ~/dlang/phobos, I tried the following commands: $ dmd -main -unittest -version=StdUnittest -I. -run std/.d and $ rdmd -main -unittest -version=StdUnittest -I. std/.d I have the feeling I'm missing something quite obvious. [1] https://wiki.dlang.org/Contributing_to_Phobos#Test_a_single_Phobos_module [2] https://wiki.dlang.org/Building_under_Windows#Building_Phobos_2 [3] https://github.com/dlang/phobos/blob/master/CONTRIBUTING.md
Re: static alias this and if/do/while/for
On Thursday, 22 October 2020 at 21:55:59 UTC, Jack Applegame wrote: There is a funny feature (or bug) in the D language: static alias this and static operator overloading. For example interface Foo { static { int value; void opAssign(int v) { value = v; } int get() { return value; } alias get this; } } Now we can use type Foo as if it were an lvalue/rvalue: Foo = 5; int a = Foo; int b = Foo + a; I heavily use this feature in my MCU library. It doesn't surprise me that much. What actually did was that static opIndex() works. Consider this: struct X { static int opIndex() { return 1; } } alias SliceOf(T) = T[]; enum ValueOf(T) = T[]; static assert( ! is(int[SliceOf!X] == int[ValueOf!X])); But static opIndex and friends can be useful: https://run.dlang.io/is/s15zS0 I'd actually find it awesome if we had opCallAssign and opCallOpAssign; the reason I used opIndex and not opCall is that way, one gets access to the right-hand side and to-assign parameters by reference, so no internal pointer stuff's needed. But it doesn't work inside conditionals: if(Foo) {}// Error: type Foo is not an expression while(Foo) {} // Error: type Foo is not an expression Even if we define `static opCast!bool()`. It doesn't help. Only using Foo.opCast!bool works; cast(bool) won't compile. Should this be fixed? The bool stuff should be fixed. The other direction would be a breaking change.
Re: Why is there no range iteration with index by the language?
On Wednesday, 10 June 2020 at 00:53:30 UTC, Seb wrote: It's a bit more complicated though as you need to avoid subtle breakage with ranges that return tuples that are auto-expanded like e.g. `foreach (k,v; myDict)`. Okay, I can accept that. It's a poor decision, but well, it is what it is. Anyhow, I would be highly in favor of DMD doing this. It's one of those many things that I have on my list for D3 or a D fork. Is there any "official" or at least public list for D3 suggestions? Many people here talk about it recently...
Why is there no range iteration with index by the language?
Is there any particular reason why std.range : enumerate is a thing and foreach (i, e; range) { ... } doesn't work from the get-go? I wouldn't have such an issue with it if static foreach would work with enumerate just fine. As far as I can tell, foreach (e; range) { ... } is being lowered to for (auto _range = range; !_range.empty; _range.popFront) { auto e = _range.front; ... } So why cant DMD rewrite foreach (i, e; range) { ... } to for (auto _range = range, index = size_t(0); !_range.empty; _range.popFront, ++index) { size_t i = index; auto e = _range.front; ... } Doesn't seem like a big deal, does it? I'm asking because I suspect there's an odd reason I have no idea and I whish to be educated.
Re: How to port C++ std::is_reference to D ?
On Wednesday, 13 May 2020 at 13:36:14 UTC, wjoe wrote: On Monday, 11 May 2020 at 19:08:09 UTC, Q. Schroll wrote: [...] 1. You can have variables ("data members") of reference type in structs. (They work like head-const pointers; if D had head-const or at least head-const pointers, those would be practically the same, only that references cannot be null.) [...] That's also something I don't really know how to correctly port to D. Anyways, that was insightful. Thank you very much for your explanations. Another thing that just occurred to me is generating types. Say I have an AliasSeq of types. I want to generate a list of delegates taking all of them with all combinations of `ref`ness. Example: alias list = AliasSeq!(int, char, double); I want the AliasSeq alias delegates = AliasSeq!( R delegate(int, char, double), R delegate(ref int, char, double), R delegate(int, ref char, double), R delegate(int, char, ref double), R delegate(ref int, ref char, double), ..., R delegate(ref int, ref char, ref double) ); That would be way easier if `ref` were part of the type (like const/immutable/inout/shared are).
Re: Fastest way to check using if identifier has already been defined, using static if or similar?
On Thursday, 4 June 2020 at 09:03:40 UTC, Simen Kjærås wrote: string exists(string s) { return "__traits(compiles, { mixin(\"alias _ = "~s~";\"); })"; } Little nitpicking, but D has many forms of string literals. Escaping is hard to read especially without syntax highlighting. Escaping to me is an old hack C did we shouldn't really use. string exists(string s) { return `__traits(compiles, { mixin("alias _ = ` ~ s ~ `;"); })`; } The _ as a name, to me, proves that a __traits(freshName), that returns a string that is distinct from every symbol name visible from the point it's defined, would be useful in these occasions. Because if someone used _ as an identifier in a context where the `exisits` function is used, it might fail.
Re: Is this a good tree?
On Tuesday, 2 June 2020 at 11:44:10 UTC, Vladimirs Nordholm wrote: Hello. I want to create a tree which maps sequences of numbers to data. ex: - [1, 2]-> 1 - [1, 3, 1] -> 2 - [1, 3, 2] -> 3 I have no prior knowledge of what makes a good tree, and I am unsure if what I've got is good. I mean it works, but if anyone with more knowledge of trees or D-lang would mind giving some feedback I would be more than happy. I've made a scaled-down, "in essence", runnable example of what I have here: https://run.dlang.io/is/JI8T2T For more context, my actual code (with extra boilerplate + project specific things) can be found here: https://github.com/vladdeSV/scone/blob/develop/source/scone/os/posix/input/input_tree.d Once again, any feedback is greatly appreciated. You might want to check out this: https://en.wikipedia.org/wiki/Trie Possibly, that's exactly what you're looking for.
Re: How to port C++ std::is_reference to D ?
On Saturday, 9 May 2020 at 13:44:27 UTC, Per Nordlöw wrote: On Wednesday, 6 May 2020 at 17:46:28 UTC, Q. Schroll wrote: C++'s decision to make references part of the type has some advantages, but D didn't do it because of many disadvantages. Can you outline or give a link describing the advantages of C++'s vs D's choice in this matter? Whether something is an advantage is subjective at least in some sense. So whether you in particular consider something I'll list here an advantage is basically your choice. 1. You can have variables ("data members") of reference type in structs. (They work like head-const pointers; if D had head-const or at least head-const pointers, those would be practically the same, only that references cannot be null.) 2. Templates can manipulate ref-ness and so on by type building. Notably, I had trouble writing templates that handle non-copyable types correctly at ctfe. The reason was that implicit moving (moving of temporaries) is done entirely by the compiler, but manual moving (std.algorithm.mutation.move) does do stuff (it doesn't just trick the compiler into moving casting stuff to rvalue references). 3. You can have local variables that are references. While not really different from pointers, I think they look less scary than pointers. 4. Especially in casts, you can trick the compiler into doing things without the fear of generating unnecessary code (in C++, std::move and std::forward are mere casts that you could do yourself but look awkward). Potentially, I'm missing something. Personally, I think D did the right thing making references a storage class. You can see very early in learning C++ that references are only half-way type constructors: They are not fully composable. Normally, you can have arrays and pointers to any type, but in C++ you can't have pointers to / arrays of references.
Re: How to port C++ std::is_reference to D ?
On Wednesday, 6 May 2020 at 09:07:22 UTC, wjoe wrote: Hello, I'm choking on a piece of C++ I have no idea about how to translate to D. std::is_reference In general, you can't. In D, `ref` is not part of the type, it's a "storage class", and as such it is a property that a function parameter can have alongside its type. I.e. in C++, it makes sense to ask: "Is that parameter's type a reference type?" But in D it doesn't; you could ask: "Is the parameter given by reference?" ("Does the parameter have the storage class `ref` [or `out` to be complete]?") C++'s decision to make references part of the type has some advantages, but D didn't do it because of many disadvantages.
Re: Understand signature of opOpAssign in std/complex.d
On Saturday, 9 November 2019 at 13:26:12 UTC, Adam D. Ruppe wrote: On Saturday, 9 November 2019 at 12:30:46 UTC, René Heldmaier wrote: The part i don't understand is "is(C R == Complex!R)". What does that mean? That's checking the if the template argument C is a case of Complex!R, while at the same time declaring a symbol R to hold the inner type. What's the difference of is(C R == Complex!R) to is(C == Complex!R, R) then?
Bug or Feature: `this` necessary to call function with template this parameter
struct Example { private void helper(int i, this X)() { } void funcTempl(T, this X)(T value) { this.helper!0(); // ^ Why do I need this? } } void main() { auto ex = Example(); ex.funcTempl(1); } The question is in the comment in the code. Is that intentional or a bug?
Array Vararg Template Paremeters
For a function, one can have a vararg parameter at the end like this: int sum(int[] ar ...) { /* code */ } But for templates, such a declaration is an error. Is there a specific reason why? I know I can do it and ensure all the template parameters are values and are convertible to the desired type. However, it's easier to just use an array.
For loop with separator
Probably you've come over this problem once in a while, too. You have a repeating solution, so you use a for(each) loop. Sometimes, there is an action to be performed between the end of one iteration and the beginning of the next, if there is one. The prime example is printing the comma when printing a list: There is one between any two elements, but neither is one at front or behind the last one. Typical solutions I employed were: 1 Handling the first element separately 2 Condition in the loop, that is false exactly for the first iteration. 1 can be done with ranges easily: if (!range.empty) { action(range.front); range.popFront; foreach (element; range) { betweenAction(); action(element); } } This approach is clearly quite verbose for the problem, but there's nothing done unnecessarily. 2 can be done easily, too: foreach (i, element; range) { if (i > 0) betweenAction(); action(element); } While 2 is less code, it's prone to be checked every iteration. Note that 2 is rather D specific in its length. It can be done in other languages, but is more verbose. Is there a cleaner solution that I missed?
How to compile my DMD fork?
Basically the headline. I want to try to implement my DIP. I've already forked DMD from GitHub. Now, what would I have to do in order to get a D compiler with my changes? I have Windows on x86-64 and Visual Studio on my machine.
Re: Parameter pack expansion
On Thursday, 30 May 2019 at 20:20:47 UTC, Tomas wrote: I'm very new to D, coming from C++ I'm missing parameter pack expansion and fold expressions. I also miss the expansion operator and fold expressions. In D, there is no such thing, and simulating it in a general way has so much friction, I just used string mixin to solve these. I even thought about writing a DIP, but I think, it wouldn't make it. In my static indexing DIP [1], there is a suggestion to add an expansion operator, but that would only work on sequences and similar things. If it would be implemented, you could place your parameter pack into a Tuple-like structure with an opDispatch that returns such a Tuple again, but the contents would be the member components "projection" to the member. It's doable[2], but the lack of indexing the pack is the main blocker. If you look closer, the DIP proposes to make "pack..." work by replacing it with pack[0], ..., pack[$ - 1] if the indexing and length are there to do it. The DIP doesn't give you parameter or type packs, it gives you what you need to implement them; still, fold expressions are still not possible. They are rather easy to implement using D's template mechanisms and/or string mixin mechanisms. The projections to the members in [2] are an example of a fold expression. [1] https://github.com/dlang/DIPs/pull/155 [2] https://run.dlang.io/is/tIxmQS
Alias to template instance wokrs, but non-template does not?
I have the rather strange question: Why does this work? struct S { int value0; alias opApply = opApplyImpl!(int delegate(ref int)); //1 int opApplyImpl(DG : int delegate(ref int))(scope DG callback) //2 { if (auto result = callback(value0)) return result; return 0; } } @safe pure nothrow @nogc unittest { S xs = S(3); int sum = 0; foreach (x; xs) sum += x; assert(sum == 3); } But replacing Lines //1 and //2 with int opApply(int delegate(ref int) callback) (replacing the alias to a template instance by equivalent(?) non-template code) does not. As far as I know, template instantiation should make them exactly the same thing. The spec does not say anything to this. Even after replacing //1 by alias opApply = opApplyImpl!(int delegate(ref int) @system); //1 i.e. marking the callback @system explicitly, the @safe unittest will still compile! Using xs.opApply((ref int x) { sum += x; return 0; }); in the unittest directly makes it fail. The compiler claims as expected that the template instance is not satisfy the conditions for either attribute on the unittest. But somehow, it does respect attributes. An un-@safe unittest like this static bool b = false; // some global state to break pure static foreach (i; 0 .. 4) { version(failure) @safe pure nothrow @nogc unittest { static immutable exc = new immutable Exception(""); S xs = S(3); int* p = &xs.value; // some pointer to break @safe-ty foreach (x; xs) { static if (i == 0) { p = new int(x); } // allocates static if (i == 1) { ++p; } // un-@safe static if (i == 2) { b = true; } // impure static if (i == 3) { throw exc; } // throws Exceptions } } } actually shows that any single attribute can be failed, suggesting it is the same for all. Is there some attribute magic in the compiler's opApply rewriting? It should be mentioned. I've filed a bug report [1] some time ago. I'm posting here, because I want to understand what's going on here. A runnable example is here: https://run.dlang.io/is/KQ0tmL [1] https://issues.dlang.org/show_bug.cgi?id=19706
Re: Access outer member of struct from inner struct
On Tuesday, 2 April 2019 at 18:52:07 UTC, Jacob Carlborg wrote: On 2019-04-02 20:44, Q. Schroll wrote: After removing the calls to writeln, the error I get is: `this` for `read` needs to be type `Outer` not type `Inner` You cannot access stuff in Outer because Inner objects are not outer objects and don't implicitly own an Outer object. In your Inner method `write`, there is no Outer object present at all to call the method on. It works if the struct is nested inside a function [1]. I thought it would work nested inside a struct too. [1] https://dlang.org/spec/struct.html#nested The reason it works inside a function is that the struct has a hidden pointer to the function context. The function's local values actually exist when an object of that struct type is being instantiated. The main difference between a struct nested in a function and one inside another struct is that the one in a function cannot¹ be created outside of that function while constructing the latter is possible the way you think it is: Outer.Inner innerObj = Outer.Inner(parameters); ¹ You can using reflection and stuff like that, but it's still broken if it uses the context.
Re: Access outer member of struct from inner struct
On Tuesday, 2 April 2019 at 18:20:09 UTC, Andrey wrote: Hello, In this example how can I access the members "read" and "q" of struct Outer from Inner struct? struct Outer { ulong q = 1; Inner inner; void read(ulong value) { q += value; } void run() { q.writeln; read(5); } struct Inner { void write(string text) { read(text.length); writeln(q); } } } void main() { Outer ttt; ttt.run(); } During compilation I get: onlineapp.d(55): Error: this for read needs to be type Outer not type Inner onlineapp.d(56): Error: need this for q of type ulong After removing the calls to writeln, the error I get is: `this` for `read` needs to be type `Outer` not type `Inner` You cannot access stuff in Outer because Inner objects are not outer objects and don't implicitly own an Outer object. In your Inner method `write`, there is no Outer object present at all to call the method on.
How to attach function attributes to delegate type?
For any type constructors like const, I can use ConstOf!T to get `T` with const attached. For a delegate/function type DG, e.g. int delegate(int), how can I get the @safe version of that type, i.e. int delegate(int) @safe? I tried alias SafeOf(DG) = DG @safe; but it didn't compile. The case is not @safe-specific; it's the same for all function attributes.
Re: My template tuple code does not compile
On Wednesday, 27 February 2019 at 03:53:35 UTC, Victor Porton wrote: After following your suggestion to rewrite it with Stride it does not work either. I assume the error is somehow related to allSatisfy!. https://github.com/vporton/struct-params-dlang/blob/c1adc86672f46fd6b743903cc270dceef120a8fe/source/struct_params.d Please help. It is important for both D community and world at large. In static assert(allSatisfy!(x => isType!x, Types) && ... you use `allSatisfy` as if it took a lambda function or something like that. It does not. It takes a expects a template. First things first: The spec¹ says that allSatisfy!(F, T) «tests whether all given items satisfy a template predicate, i.e. evaluates to F!(T[0]) && F!(T[1]) && ... && F!(T[$ - 1]).» Here, `F` is not a lambda, it's a template. In your case, you can use `isTypeTuple!Types` from the library² to check what you intend to check. For the values, unfortunately there is no library function to check that they are all strings. A specific solution is to use a (static) template enum bool isStringValue(alias x) = is(typeof(x) == string); and feed it to `allSatisfy`: allSatisfy!(isStringValue, Names) ¹ https://dlang.org/library/std/meta/all_satisfy.html ² https://dlang.org/phobos/std_traits.html#isTypeTuple
Why is my @pure function @system when placed in a struct?
I have a template function `fImpl` I whish to instantiate manually using the new name `f`. Reason is simple: `f` should not be a template, but overloading it makes it easier that way. Nothing's more simple in D: int fImpl(T)(T value) { return cast(int) value; } alias f = fImpl!int; alias f = fImpl!long; It works perfectly used like that. In my case, `T` isn't just a simple type, it's a delegate type. So it's rather like this: alias BaseDG = int delegate(ref int); int fImpl(DG : BaseDG)(scope DG callback) { // NB: this is @safe iff callback is @safe int x = 0; return callback(x); } alias myDG = int delegate(ref int) @safe; alias f = fImpl!myDG; When I ask the compiler, if `f` is @safe, it tells me: Hurray, it is! pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @safe For whatever reason, when I put the code in a struct, the @safe testing line tells me, it's @system now. struct S { // static: // static or not does not matter alias BaseDG = int delegate(ref int); int fImpl(DG : BaseDG)(scope DG callback) { return 0; } alias myDG = int delegate(ref int) @system; alias f = fImpl!myDG; pragma(msg, __traits(getFunctionAttributes, f)); // tells me: `f` is @system } I have no idea why. It is irrelevant if the function template is `static` or even does not call the callback.
Re: My template tuple code does not compile
On Tuesday, 26 February 2019 at 22:56:37 UTC, Victor Porton wrote: On Tuesday, 26 February 2019 at 22:51:15 UTC, Q. Schroll wrote: Grouping arguments could be done, but from my experience, it does not buy you anything; rather it makes it worse. Better just deal with heterogeneous stuff just like std.typecons.Tuple does. After fixing the error you pointed me, it does not work too: mixin ProviderParams!("S", ((int, "x"), (float, "y"))); Also: Can I nevertheless group arguments? No, not the way you do. The module std.meta defines AliasSeq as follows: alias AliasSeq(X...) = X; It is literally equivalent to template AliasSeq(X...) { alias AliasSeq = X; // "eponymous template member" } In mixin ProviderParams!("S", ((int, "x"), (float, "y"))); the parenthesized stuff like (int, "x") is invalid in terms of formal grammar. You could use AliasSeq!(int, "x") if you really want to display grouping in your source code. Note however that this does not do anything. The sequence is being flattened by the compiler, i.e. mixin ProviderParams!("S", AliasSeq!(AliasSeq!(int, "x"), AliasSeq!(float, "y"))); is exactly the same as mixin ProviderParams!("S", int, "x", float, "y"); which I wrote in my answer. When you don't use a eponymous template member, you can access them manually: template Pack(X...) { alias Contents = X; // not "eponymous template member" } Using this, you can create what I call packs. For some template T, while T!(AliasSeq!(int, bool), AliasSeq!(float, string, long)) is the same as writing T!(int, bool), the T!(Pack!(int, bool), Pack!(float, string, long)) is different from T!(int, bool, float, string, long). In the AliasSeq template, the eponymous template member feature of D immediately expands the sequence. If the template T is defined like this: template T(Args...) { .. } In the AliasSeq case, Args[0] is int, Args[1] is bool, Args[2] is float, ... In the Pack case, Args[0] is Pack!(int, bool), Args[1] is Pack!(float, string, long), and Args[0].Contents[0] is int, Args[0].Contents[1] is bool, Args[1].Contents[0] is float ... I've used Packs once to get the Cartesian product of an AliasSeq of Packs. It is a mess. I'd only use Packs when absolutely necessary; in your case, it does not seem so. In your case, you seem to need some initial thing "S" and then pairs of things. template you_name_it(Arg, args...) if (args.length % 2 == 0) // ensures pairs { static foreach (i; args.length / 2) { // access the type by args[2*i] // access the name (or whatever) by args[2*i+1] } } You could get the sequence of types and the sequence of names using alias Types = Stride!(2, args); alias Names = Stride!(2, args[1 .. $]);
Re: My template tuple code does not compile
On Tuesday, 26 February 2019 at 21:43:31 UTC, Victor Porton wrote: Compilation of unittest at the bottom of this file fails with an error. What is my error? I cannot tell you, why exactly you get these error messages. I can explain you the probable cause of the errors. I have not tested anything of what I tell you, as it is very vague. You have the line ProviderParams("S", ((int, "x"), (float, "y"))); Why do you even expect it to compile? First, ProviderParams is a mixin template, so you'd need to instantiate it with the ! operator. Then, the expressions (int, "x") and so on do not make sense in D. You could have compile-time tuples (using AliasSeq from std.meta) containing types and other compile-time known stuff, but it wouldn't help directly. You'd use the mixin template like this: mixin ProviderParams!("S", int, "x", float, "y"); ^-- necessary ^-- necessary Grouping arguments could be done, but from my experience, it does not buy you anything; rather it makes it worse. Better just deal with heterogeneous stuff just like std.typecons.Tuple does. You should definitely comment your code. Explain what you intend to do. It helps people helping you.
Re: Syntax for Pointer to Class
On Friday, 25 January 2019 at 20:31:29 UTC, H. S. Teoh wrote: On Fri, Jan 25, 2019 at 08:12:33PM +, Q. Schroll via Digitalmars-d-learn wrote: Say I have a class C and I want a pointer to a C handle. Note that taking the address of `C` will actually give you a pointer to the reference, not the pointer to the class instance itself. I know. This is precisely the thing I asked for: A pointer to a handle. I called it handle for exactly this reason. For that to be valid, you'll need to store your class reference somewhere first, since it's invalid to take the address of an rvalue Yes. `&new C(...)` looked to wrong for me to even consider trying. C c = new C(...); C* ptrToRef = &c; So the answer is no. At least not that simple. Be warned that the pointer will become invalid when the reference `c` goes out of scope, even if the object itself is still live (via another reference), because the pointer is pointing to the class reference rather than the actual object. That's kind of obvious if you get remembered, but thanks. I wasn't considering this as I wanted the handle to live on the heap anyway --- the same way for a struct `S`, the pointer pointed to by `S** ptr = new S*(new S(...));` lies on the heap. I'll use C* ptr = &[ new C(...) ][0]; for now. It looks ugly, but it does the job.
Syntax for Pointer to Class
Say I have a class C and I want a pointer to a C handle. I tried the following pieces of syntax: C* obj = new C(); // gives me a C C* obj = new C*(); // gives me a C** C* obj = C*(); // refuses to compile Is it even possible? This sounds so newbie... I know it's fairly simple with structs: S() gives me a struct instance, new S() gives me a ptr to a struct instance.
Re: Am I misusing with?
On Saturday, 19 January 2019 at 20:38:00 UTC, faissaloo wrote: On Saturday, 19 January 2019 at 20:07:34 UTC, Rubn wrote: On Saturday, 19 January 2019 at 17:49:31 UTC, faissaloo wrote: [...] If you look at the implementation, "lines" is a struct. https://github.com/dlang/phobos/blob/v2.084.0/std/stdio.d#L4330 [...] Ah that makes some sense, thanks for the explanation. If you import symbols explicitly, you'd have known. Probably in your code: import std.file; What should be there: import std.file : File, lines; If lines is a member of the File struct, the import fails. If lines is not a member of File, not importing it fails. You get more detailed information. Using import bind lists [1] usually is a good idea. [1] https://dlang.org/spec/module.html#import-declaration
Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue?
On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov wrote: On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote: Ah. Is there any case where you would not want to do that when you have a T value as parameter? Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects. The spec actually forbids you creating self referencing structs. DIP 1014 tackles that. For the spec, see https://dlang.org/spec/garbage.html#pointers_and_gc
Re: Move and CTFE
On Wednesday, 30 May 2018 at 21:02:07 UTC, Jonathan M Davis wrote: On Wednesday, May 30, 2018 20:42:38 Q. Schroll via Digitalmars-d-learn wrote: It seems one cannot std.algorithm.mutation.move objects explicitly. Say I have a non-copyable type [...] It fails because move() cannot be executed at compile time. The reason "memcpy cannot be interpreted at compile time, because it has no available source code" sounds very suspicious. Why is it suspicious? memcpy is a C function, and you can't call C functions during CTFE precisely because the compiler doesn't have their source code. You can't call D functions either if the compiler doesn't have their source (e.g. if you're using a .di file to hide the implementation). I definitely do understand the error message and it makes sense that it fails the way it's implemented. However, it makes no sense that moving as a concept can fail at CTFE. That's what I find suspicious. [Maybe 'suspicious' isn't the right term; I couldn't express it better.] You can move rvalues at CTFE which proves that the compiler can do it. Shouldn't it be possible to move at CTFE, too, or does it mean, non-copyable types are practically unusable for CTFE? You can't do much in the way of pointer or memory manipulation during CTFE (e.g. no pointer arithmetic or reinterpret casts). So, I don't see how a move could be done during CTFE. Even if the source for memcpy were available during CTFE, I suspect that it wouldn't be allowed due to the lower level stuff that it does. That's the explanation why probably all currently possible library alternatives to memcpy would fail. I suspected that when encountering the error, but still wonder why memcpy or other low-level stuff is even necessary to accomplish something the compiler is perfectly able to do. From what I see, the reason for the hack is lack of expressiveness: We don't have rvalue-refs in D (which I find good) so, currently, there is no cast-solution as in C++. So for a proper move() that works at CTFE, we'd need some specific tool. I have no idea of the details on how the compiler handles lvalues. Would it make sense to add a compiler trait, specifically to solve moving? Like __traits(move, lvalue_expression) [name up for discussion] that is identical to lvalue_expression with the exception that the (lvalue/rvalue) flag (or whatever it is) is set to "rvalue". Basically, it's the C++ solution: After the "cast", the compiler will proceed and pretend it is an rvalue and therefore initiate moving. Do you think adding a trait to make move() and swap() work at CTFE is worth it? A quick search showed me the class "Expression" has "virtual bool isLvalue();" so it might be easy as wrapping and hooking that virtual method. To me, [1] highly suggests that it works. [1] https://github.com/dlang/dmd/blob/master/src/dmd/expression.d#L1219
Move and CTFE
It seems one cannot std.algorithm.mutation.move objects explicitly. Say I have a non-copyable type struct NoCopy { int payload; // some payload pure nothrow @nogc @safe @disable: this(this); // make it non copyable } that is being used in a compile-time function evaluation where values are being moved. int f() pure nothrow @nogc @safe { import std.algorithm.mutation : move; NoCopy nc = NoCopy(1), nc2 = NoCopy(3); nc = move(nc2); return 0; } static assert(f() == 0); // trigger CTFE It fails because move() cannot be executed at compile time. The reason "memcpy cannot be interpreted at compile time, because it has no available source code" sounds very suspicious. Shouldn't it be possible to move at CTFE, too, or does it mean, non-copyable types are practically unusable for CTFE?
Re: What's the purpose of the 'in' keyword ?
On Sunday, 27 May 2018 at 16:00:15 UTC, Jonathan M Davis wrote: [...] Honestly, I'd suggest that folks never use in at this point. There's zero benefit to it. [...] Exactly. If you intend const, just write const. If you intend const scope, write const scope.
Re: Why The D Style constants are written in camelCase?
On Wednesday, 9 May 2018 at 09:38:14 UTC, BoQsc wrote: The D Style suggest to camelCase constants, while Java naming conventions always promoted uppercase letter. Is there an explanation why D Style chose to use camelCase instead of all UPPERCASE for constants, was there any technical problem that would appear while writing in all UPPERCASE? Java language references: https://en.wikipedia.org/wiki/Naming_convention_(programming)#Java https://www.javatpoint.com/java-naming-conventions http://www.oracle.com/technetwork/java/codeconventions-135099.html https://medium.com/modernnerd-code/java-for-humans-naming-conventions-6353a1cd21a1 D lang reference: https://dlang.org/dstyle.html#naming_constants It is really helpful to write generic code. E.g. you use `myRange.empty` and you do not care what `empty` actually is. The range could be infinite and define `enum empty = false;` If you use an uppercase identifier like `EMPTY`, generic code breaks; if you don't but do otherwise, where is the boundary? The only solution is, you don't spell it different if something is a compile-time constant or not. It is even possible that some name can refer to a type, which is usually spelled with the first letter uppercase, or a value. On [1] it reads: `hook` is a member variable [of type `Hook`] if it has state, or an alias for `Hook` [the type itself] otherwise. So, generally, anything is spelled camelCase except declared types as classes, interfaces, structs, unions, and aliases for things definitely known to be types. [1] https://dlang.org/phobos/std_experimental_checkedint.html#.Checked.hook
Re: Purity of delegate-style toString
On Tuesday, 1 May 2018 at 12:03:15 UTC, ag0aep6g wrote: On 05/01/2018 01:44 PM, Per Nordlöw wrote: In which cases (if any) is it possible to make a delegate-style implementation of toString such as void toString(scope void delegate(const(char)[]) sink) const @trusted pure { // sink("..."); // sink.formattedWrite!"..."(...); } pure? You have to mark `sink` as pure, too: void toString(scope void delegate (const(char)[]) pure sink) const @trusted pure Then the toString method itself works, but it may not be callable by other code that wants to use an impure sink. For example, `format` works, but `writeln` doesn't: struct S { void toString(scope void delegate(const(char)[]) pure sink) const @trusted pure { import std.format: formattedWrite; sink("..."); sink.formattedWrite!"%s"(" ..."); } } void main() { import std.format: format; import std.stdio: writeln; writeln(format("%s", S())); /* Ok. Prints "... ...". */ writeln(S()); /* Nope. writeln would like to use an impure sink. */ } By the way, you shouldn't mark toString as @trusted when `sink` is @system. I had similar issue for opApply. The generalized problem is, the attributes (pure, nothrow, @safe, @nogc) are too strong on functionals (i.e. functions taking function/delegate arguments). We could (and IMO should) weaken the attributes to mean: the same as always, *assuming all function/delegate arguments have it*. Concrete example, say your `toString(scope void delegate(const(char)[]))` is conceptually pure, i.e. if `sink` is a pure function (by static typing), `toString(sink)` acts pure, and for impure `sink`, `toString(sink)` possibly impure. So purity of the functional `toString` depends on the purity of its arguments; that is very natural as most functionals call their parameters. The current state makes attributes virtually useless for functionals. Often, toString can be templetized without drawback (except virtual functions), but opApply cannot. opApply must not be a template to enable type deduction for the variable.[1] Making attributes act structurally has almost no consequences in terms of breakage; just more functions can be pure/nothrow/@nogc/@safe. It would make functionals impure/unsafe/.. that do not call their argument. The question is, in which contexts are they used and is it an issue -- is it a greater issue than this. Complete example what the change would do: Say you have void toString(scope void delegate(const(char)[]) sink) pure { sink("Example"); } toString is a pure functional, so calling it is pure iff the argument itself is. The compiler statically knows if the argument is pure and can infer the purity of the expression. [1] https://dlang.org/spec/statement.html#foreach_over_struct_and_classes (We could define very general special cases where type deduction can be archived, e.g. opApply(DG : int delegate(Args))(DG).)
Overload Resulution Template with 2 Functions vs. 2 Templates difference
Why is there a difference between struct S { template func(T) { enum impl = "whatever string"; auto func(T arg) { mixin(impl); } // eponymous template auto func(T arg) const { mixin(impl); } // eponymous template } } and struct R { private enum impl = "whatever string"; auto func(T)(T arg) { mixin(impl); } auto func(T)(T arg) const { mixin(impl); } } And what is the difference exactly? I know that auto func(T)(T arg) { mixin(impl); } is strictly equivalent to template func(T) { auto func(T)(T arg) { mixin(impl); } } so the difference is just 2 templates 1 function each vs. 1 template 2 functions. I don't have a simple example; here is no difference observable. The issue is with std.typecons.Tuple.opCmp; there are two templates and I tried making it one, as the implementation is identical. Unfortunately, one cannot use `inout` for more or less obcious reasons. An attempt to put them into one template (as for struct S) does not work either, but I don't understand why. Solution like struct R works. Is there a complete reference for how overload resolution works in D, including implicit template instantiation?
simple DIP1000 test fails?
I've tried to get into the changes by DIP1000 and discovered this: struct S { ref S id() return { return this; } } void main() { S* p = &S().id(); } Should it really compile? (rdmd -dip1000 .\test_return_ref.d)
Re: Why 2 ^^ 1 ^^ 2 = 2?
On Saturday, 28 October 2017 at 00:14:15 UTC, Ivan Kazmenko wrote: For an argument, the TEX command "^" accepts either a single character or a bracket-enclosed string of arbitrary length. So $3^3^3$ indeed transforms to ${3^3}^3$, but not for some deeper reason this time. On my TeX compiler, $3^3^3$ makes it give a warning/error.
if (auto x = cast(C) x)
For a class/interface type `A` and a class `C` inheriting from `A` one can do A a = getA(); if (auto c = cast(C) a) { .. use c .. } to get a `C` view on `a` if it happens to be a `C`-instance. Sometimes one cannot find a good new name for `c` while there is no advantage of accessing `a` when `c` is available. D does not allow to shadow `a` in the if-auto declaration for good reasons. How about relaxing the rule for cases like these, where the rhs is the lhs with a cast to derived? if (auto a = cast(C) a) { .. use a typed as C .. } One can think of `a` being *statically* retyped to `C` as this is a (strictly) better type information. Internally, it would be a shadowing, but it does not matter as the disadvantages don't apply (if I didn't miss something).
Re: BigInt foreach loop
On Friday, 4 August 2017 at 16:40:08 UTC, Stefan Koch wrote: [..] foreach(x;A .. B) it's lowerd to auto limit = B; auto key = A; for(auto x = key;key < limit;++key) { // use x } That's enough to know that the foreach loop does not reuse the space for the iteration variable. That was what I cared about.
BigInt foreach loop
One can do BigInt n = returnsBigInt(); foreach (i; BigInt(0) .. n) { .. } How is this implemented? The code for BigInt is very large and I didn't find it. And is it more efficient than for (BigInt i = 0; i < n; ++i) { .. } as incrementing is a costly operation?
Re: Search for, o/w create element for AA
On Monday, 19 June 2017 at 16:54:46 UTC, Ali Çehreli wrote: On 06/19/2017 08:19 AM, Q. Schroll wrote: Can't I tell the AA to set a value for a given key if it doesn't already have one (1) with only one lookup, and (2) in a safe way? aa.get(key, defaultValue) https://dlang.org/spec/hash-map.html#properties Ali aa.get returns the defaultValue if the key is not in the AA, but does not add the key-value pair (x, defaultValue) to the AA. I'd find it rather surprising if it did.
Search for, o/w create element for AA
Trying to implement some random function I encountered this: uint randFunc(uint x) { static uint[uint] vals; if (auto r = x in vals) return *r; return vals[x] = uniform!uint(); } I have to lookup x twice and it seems that there is no way around it. Can't I tell the AA to set a value for a given key if it doesn't already have one (1) with only one lookup, and (2) in a safe way? For the semantics, that should behave like this: V set(K, V)(ref const(V)[const(K)] aa, auto ref const(K) key, lazy const(V) value) { if (auto valPtr = key in aa) return *valPtr; // cast away const as initialization is okay: return (cast() aa[key]) = value(); } The function is dual to AA's get. It would make it possible for an AA with const value type to have values added which is perfectly fine for arrays. All I have seen so far, one cannot safely add values to them as initialization and assignment cannot be distinguished.
Re: Function Template Overloading
On Wednesday, 15 March 2017 at 02:33:36 UTC, ketmar wrote: Q. Schroll wrote: void test(T)(T* arg); void test(T)(ref T arg); Let p be any pointer. Why is test(p) not an ambiguity error? Why is the second overload chosen? 'cause `ref T` is more generic than `T*`. think of it as "greedy matching": compiler first tries to match `int*`, and if that failed, it tries `int`, for example. and `int*` matches the second template, so compiler choosing it. Wouldn't it be better vice versa, the more specific pattern to be prioritized? And as it actually *can* match both, is it a compiler-bug not to be an ambiguity error?
Function Template Overloading
void test(T)(T* arg); void test(T)(ref T arg); Let p be any pointer. Why is test(p) not an ambiguity error? Why is the second overload chosen? Making the first one take auto ref T* lets the compiler choose the first. Making the second one non-ref lets the compiler give me an ambiguity error. Template Functions are not mentioned in the spec, at least not on https://dlang.org/spec/function.html#function-overloading, but it suggests that ref should not make the decision if it can be bound to.
Re: How to compile against GitHub fork of Phobos?
On Tuesday, 7 March 2017 at 02:30:21 UTC, ketmar wrote: Q. Schroll wrote: On Tuesday, 7 March 2017 at 01:45:48 UTC, Adam D. Ruppe wrote: You pass your modified file to the compiler: dmd yourfile.d format.d The format.d there can be a copy of the one from phobos (or a fork or whatever) and since you passed it explicitly on the command line, it takes precedence over the one in the library. You still import it as std.format. You can do that with as many modules as you like. I just tried it out. dmd myfile.d phobos/std/format.d worked fine, but interestingly, rdmd myfile.d phobos/std/format.d did not. The latter definitely takes format from the library. I have no idea why. rdmd doesn't work like dmd. here, it just passing "phobos/std/format.d" as command line argument to "myfile.d". You're right. I should've known that. By bad ... Thanks for your replies. They were very helpful.
Re: How to compile against GitHub fork of Phobos?
On Tuesday, 7 March 2017 at 01:45:48 UTC, Adam D. Ruppe wrote: You pass your modified file to the compiler: dmd yourfile.d format.d The format.d there can be a copy of the one from phobos (or a fork or whatever) and since you passed it explicitly on the command line, it takes precedence over the one in the library. You still import it as std.format. You can do that with as many modules as you like. I just tried it out. dmd myfile.d phobos/std/format.d worked fine, but interestingly, rdmd myfile.d phobos/std/format.d did not. The latter definitely takes format from the library. I have no idea why.
How to compile against GitHub fork of Phobos?
I have a fork of the standard-library in the folder "phobos". In version 2.072.1 of the compiler, I could use code like void main() { import phobos.std.format; /* code for checking my changes to format */ } compiled with $ dmd -I"phobos" test_format.d in the parent folder of phobos. It worked fine. I've updated the compiler today and get an error message: module std.typecons from file phobos\std\typecons.d must be imported with 'import std.typecons;' But if I do so, it imports the one from the standard library attached to the compiler. Is it a regression? Should the old version have rejected my code? I don't see any possibility to test specific changes in modules of my fork. I've just read https://wiki.dlang.org/Starting_as_a_Contributor#Building_D, but it didn't help me out.
Why don't Function Lambdas Cast to Delegate?
Why don't lambdas cast to a delegate if they are of type R function(Args)? I don't see any reason to that; a lambda should be a delegate type by default, and a function only as a special guarantee/optimization. It just makes them cumbersome to use with toDelegate. Probably there is a good reason why R function(Args) does not implicitly cast to R delegate(Args); I can imagine something internally (memory layout etc.) causes that. I'd just like to know.
Using opApply and Attributes
When using functions with delegate (or function ptr) parameters which should comply with some attributes, I cannot call the delegate in the function what makes it pretty useless (I haven't done research, but I claim that generally most functions taking delegate parameters call them). void f1(void delegate(int) dg) // cannot be pure ... { dg(1); // ... due to this call. } void main() pure { f(x => 2*x); // Error, f is impure. } One has to overload the function like auto f(delegate(Arg arg) @attrib dg) @attrib; auto f(delegate(Arg arg) dg); for each combination of attributes available (today 4, worst case is 16 overloads), could be more in the future. Even worse (due to bug 15859, see [1]) overload resolution on opApply does not work properly. Making opApply a template is a real solution for various reasons (virtual functions, no type inference on the delegate, etc.). For opApply, using the range interface (empty, front, popFront) is not a real solutions either because opApply can be truly recursive. Those can then only have a range interface through generators via fibers which have an overhead (and make them non-@nogc). How can I have relative-@attrib functions without unnecessary manual overloading? (relative: if all called parameter delegates have it, then the function has it) Generally, are relative attributes worth an enhancement? [1] https://issues.dlang.org/show_bug.cgi?id=15859
std.algorithm.iteration.each requires opApply to have ref elements?
Why does it do that? And seemingly it does not require it for opApply with more than two arguments.
Re: inferred vs. annotated attributes
On Saturday, 10 September 2016 at 09:38:15 UTC, Lodovico Giaretta wrote: On Saturday, 10 September 2016 at 08:23:35 UTC, Q. Schroll wrote: Is there a difference between inferred and annotated attributes? Example: struct X(T) { this(S)(in S[] arr) // inferred pure { } } void main() pure { X!uint mut = [ 1, 2 ]; // proves inference (cf. main is pure) // immutable X!uint imm1 = [ 1, 2 ]; // auto imm2 = immutable X!uint([1, 2]); } The commented lines yield error messages claiming the constructor cannot deduce function from argument types !()(int[]) immutable, however it can, if "pure" is explicitly annotated. Is this a bug or did I get something wrong about inference / unique expressions? A method (included ctors) that is not annotated const, nor immutable, nor inout, is implicitly mutable. This implies that your ctor is mutable, and as such it cannot create immutable instances. IIRC, a pure ctor can construct any objects (including immutable and shared). If you add another ctor marked immutable, everything works. An alternative is to mark the ctor as inout. Technically I know. The minimal example only explains the problem/bug. My real constructor does do things where I don't want inout attributes if I can avoid. I tested this solution and it works, but I'm not sure if it is by design. Sure. It did for me, too. The question is: Why does annotating an inferred attribute make a difference? (Or it doesn't and I don't see it all the time.)
inferred vs. annotated attributes
Is there a difference between inferred and annotated attributes? Example: struct X(T) { this(S)(in S[] arr) // inferred pure { } } void main() pure { X!uint mut = [ 1, 2 ]; // proves inference (cf. main is pure) // immutable X!uint imm1 = [ 1, 2 ]; // auto imm2 = immutable X!uint([1, 2]); } The commented lines yield error messages claiming the constructor cannot deduce function from argument types !()(int[]) immutable, however it can, if "pure" is explicitly annotated. Is this a bug or did I get something wrong about inference / unique expressions?
Re: opAssign return type
On Friday, 2 September 2016 at 17:33:22 UTC, Steven Schveighoffer wrote: On 9/2/16 1:18 PM, Q. Schroll wrote: When overloading assignment, I've been taught in my C++ course to return a reference to the lvalue being assigned to. This is easily possible in D, but in Phobos it is used rarely and in Ali Çehreli's Book it is neither taught to do so. Sure, you can do this. Is there any reason to it? To me it seems very obvious to do it like in C++. I can imagine a reason is to avoid issues with lifetime. It's dangerous to return this as a reference in most cases, because this is implicitly passed by reference even for rvalues. However, for opAssign, you generally are sure you don't have an rvalue. Interestingly the compiler does not allow rvalue = expr but it does however allow rvalue.opAssign(expr). In any case, there's nothing wrong with it technically, it should work. -Steve There is no possibility to enforce some method is only available for lvalue this?
opAssign return type
When overloading assignment, I've been taught in my C++ course to return a reference to the lvalue being assigned to. This is easily possible in D, but in Phobos it is used rarely and in Ali Çehreli's Book it is neither taught to do so. Is there any reason to it? To me it seems very obvious to do it like in C++. The question came up in the discussion of a PR: https://github.com/dlang/dlang.org/pull/1466
Re: Use dup on Containers with const Elements
On Friday, 29 July 2016 at 19:24:59 UTC, Steven Schveighoffer wrote: On 7/29/16 3:00 PM, Q. Schroll wrote: Cases to consider: Arrays and AAs with const(T) Elements, where T is a value or a reference type respectively. [snip] Questions: (1) Why do I have to specify the type here? Why does inference fail? (2) Why not just S[S]? The copy of a const S is a S so why is the copy of a (const S, const S)-pair not just (S, S)? array.dup has the meaning to copy the original but make the elements mutable. At least, that's what it was when it was handled by the compiler/runtime. I do understand the reasons why I can't simply copy const reference type objects to mutable. It just makes sense as the referred object is still const. I thought of dup being there for convenience and performance reasons. The spec says about dup: "Create a dynamic array of the same size and copy the contents of the array into it." It has not been clear to me it intends to make the elements mutable. For my intention, I thought of dup making a shallow copy--which is a deep copy on value types so it can drop the const then. So the reason for 1 is that you can't convert const(C) to just C without a cast, so you must specify the type. The implementation is made so that I have to. This one is obvious then. I'm not certain about AA, as I don't remember how dup was defined on them. -Steve I just wonder if it is a bug. If it is true, then it's a misfeature or badly specified function.
Use dup on Containers with const Elements
Cases to consider: Arrays and AAs with const(T) Elements, where T is a value or a reference type respectively. class C { } struct S { } const(S)[] varr; const(C)[] carr; const(S)[S] vaav; const(C)[S] caav; const(S)[C] vaac; const(C)[C] caac; pragma(msg, typeof(varr.dup)); pragma(msg, typeof(carr.dup!(const C))); // (1) pragma(msg, typeof(vaav.dup)); pragma(msg, typeof(caav.dup)); pragma(msg, typeof(vaac.dup)); pragma(msg, typeof(caac.dup)); yields S[] // ok const(C)[] // ok const(S)[S] // (2) const(C)[S] // ok const(S)[C] // ok const(C)[C] // ok Questions: (1) Why do I have to specify the type here? Why does inference fail? (2) Why not just S[S]? The copy of a const S is a S so why is the copy of a (const S, const S)-pair not just (S, S)?
Re: Associative array of const items
On Thursday, 30 June 2016 at 17:08:45 UTC, Jonathan Marler wrote: Is there a way to have an associative array of const values? I thought it would have been: const(T)[K] map; map[x] = y; but the second line gives Error: cannot modify const expression. I would think that the const(T)[K] would behave similarly to const(T)[], where you can modify the array, just not the individual elements, but associative arrays don't seem to have the same semantics. Is there a way to achieve these semantics with an associative array? It is possible to initialize the array with a AA literal as const(int)[string] aa = [ "1": 1, "2": 2 ]; but AAs don't have opIndexAssign etc. The reasonable things you do to const(T)[] is shorten it or reassign it completely. For an AA, this is removing elements or adding new ones. While the first is without problems, the problem is how to determine if aa["1"] = 1 is a (legal) initialization or (illegal) reassignment of a const(T). Unfortunately, there is no function to add key-value-pairs that throws an Error if the key is already there or else reinitializes the value.
Formatted Output: Exact number of Decimal Places
Lets say I want to print a table with floats. How can it be formatted like that: | 2.4 | | 12.2 | | 8.131 | | 17.44 | Also acceptable is | 2.400 | | 12.200 | | 8.131 | | 17.440 | but not | 02.4 | | 12.2 | | 08.131 | | 17.44 | or any other solutions with leading zeros.
Re: pure opApply
On Thursday, 31 March 2016 at 13:51:00 UTC, Steven Schveighoffer wrote: I think it's a bug. foreach and opApply are specially coded in the compiler I think, so there's bound to be inconsistencies between them and normal overload rules. -Steve I have never filed a bug report. Should this be reported? How and where to do?
Re: foreach UFCS
On Thursday, 31 March 2016 at 13:39:25 UTC, ixid wrote: What is going on with UFCS and foreach? foreach(i;0..5).writeln; This is not UFCS; it is calling writeln on module scope. See http://dlang.org/spec/module.html#module_scope_operators Your code is semantically identical with foreach (i; 0 .. 5) { .writeln; // module scope operator! } Furthermre because there is no local variable writeln that could be confused with the imported function, the code is identical with foreach (i; 0 .. 5) { writeln; } This prints five line breaks. foreach(i;0..5).i.writeln; This will not compile. It does not compile because i is not an identifier at module scope. i is a local variable and a hypothetical i at module scope (accessible via .i) is not declared, therefore this is an error. foreach(i;0..5).writeln(i); This writes out 1 to 4 on separate lines. Is this supposed to work? I thought a.b would be rewritten to b(a) with UFCS but writeln(foreach(i;0..5)) is nonsensical and does not compile and should be the same as foreach(i;0..5).writeln; It does rewrite. But only if there is an expression beforehand the dot. Here it just isn't. The "foreach (i; 0 .. 5)" is not a complete expression.
pure opApply
Simple as that, shouldn't this work? struct X { int opApply(int delegate(string) dg) { return dg("impure"); } int opApply(int delegate(string) pure dg) pure { return dg("pure"); } } void main() { X x; string result; x.opApply( (string s) { result = s; return 0; } ); writeln(result); // does compile and prints "pure". x.opApply( (string s) { result = s; write(""); return 0; } ); writeln(result); // does compile and prints "impure". /+ (1) foreach (string s; x) { result = s; } writeln(result); // does not compile: x.opApply matches more than one declaration +/ /+ (2) foreach (string s; x) { result = s; write(""); } writeln(result); // does not compile: x.opApply matches more than one declaration +/ } Can someone explain me, why the compiler cannot resolve the right opApply? From what I know, it generates a delegate with inferred pure attribute and looks for the best match of opApply. Why does the manual rewrite work? If I've done the rewrite improperly, please tell me.
Arithmetic conversion -- warnings missing?
import std.stdio; void main() { short ss = -1; ushort us = 0; intsi = -1; uint ui = 0; if (ss < us) writeln("a"); else writeln("b"); if (si < ui) writeln("A"); else writeln("B"); } prints "aB" due to integral promotion and arithmetic conversion rules. I know it's this kind of thing: If it compiles and looks like c, it behaves the same. But why does it compile and why does it so without any warning? Is there any rationale to make this even work?