Re: Why is Phobos `Flag` so overthought ?
On Thursday, 9 May 2024 at 18:48:12 UTC, Nick Treleaven wrote: We have a tool in our box already called `true` and that solves the problem. If we had to type out the full name of every argument passed to every function ever written we may as well just adopt ObjC Cocoa style and call it StopWatchWithAutoStartBool(). Strawman. Not at all. I mean exactly that. Why do you believe this function is so important it needs to have its argument type explicitly stated, when most functions don't? Either that, or you believe all functions should. It's arbitrary and pointless.
Re: Why is Phobos `Flag` so overthought ?
On Wednesday, 8 May 2024 at 10:24:07 UTC, Nick Treleaven wrote: On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote: It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases. It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments. Flag enforces that the argument says what it relates to. `true` does not say what it relates to. Named arguments are optional, so I don't see how they could make Flag redundant. It's pointless mandatory verbosity. StopWatch ctor only takes one boolean argument. It doesn't *need* to specify what it relates to. You either already know, or you have to look it up anyway. Flags made sense when you might get the order of multiple bools confused, but if there's only one, *or* if you can use named arguments to avoid ambiguity, there's no point in demanding every parameter be a unique type. It's easy to remember I can pass a bool to a StopWatch to autostart it. It's less easy to remember that a specific unique type needs to be used, and remembering whether the name/casing of that type was Start, StartNow, StartAuto, Autostart, AutoStart, autostart, autoStart, etc. We have a tool in our box already called `true` and that solves the problem. If we had to type out the full name of every argument passed to every function ever written we may as well just adopt ObjC Cocoa style and call it StopWatchWithAutoStartBool().
Re: Why is Phobos `Flag` so overthought ?
On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote: I think this just works: ```d enum Flag : bool { no, yes } ``` ... must be a reason but I cant find it RN ;) In "properly" designed Phobos packages, it's unambiguous. Take for example std.datetime.stopwatch: ```d import std.typecons : Flag; alias AutoStart = Flag!"autoStart"; alias MyOtherFlag = Flag!"myOtherFlag"; ... //auto sw = StopWatch(true); // Not allowed //auto sw = StopWatch(MyOtherFlag.yes); // Not allowed auto sw = StopWatch(AutoStart.yes); ``` It doesn't allow a simple boolean to be used as an argument, or any other Flag as they are different instantiations of a template rather than equivalent aliases. It is however awful, cumbersome, annoying design and needs to be completely phased out now that we have named arguments.
Re: Adapting foreign iterators to D ranges
On Wednesday, 24 April 2024 at 05:08:25 UTC, Salih Dincer wrote: Yes, `opApply()` works! You just need to use `do while()` instead of `while()` because it skips the first item. It depends on the type of structure being consumed, if it provides "next" as a direct pointer then yeah you would need to consume the item first before iterating to the next in line. However some APIs provide an opaque iterator type where you call a "next" method to get the first element, IIRC Lua does something like this.
Re: Adapting foreign iterators to D ranges
On Monday, 22 April 2024 at 11:36:43 UTC, Chloé wrote: I wish to adapt this interface to a forward range for use with foreach and Phobos' range utilities. This amounts to implementing empty, front, and popFront, in terms of next and some state. But there is a choice to be made regarding the first call to next. Just to offer an alternative solution (since it sometimes gets overlooked), there is also the `opApply` approach. You don't get full forward range status, and checking whether it's empty essentially requires doing something like std.algorithm `walkLength`, but if all you need is basic iteration, it can be a simpler solution: ```d struct Range { private I iter; this(I iter) { this.iter = iter; } int opApply(scope int delegate(T* t) dg) { while (auto current = next(iter)) { if (auto r = dg(current)) return r; } return 0; } } void main() { I someIter; // = ... auto range = Range(someIter); foreach (const t; range) { writeln(*t); } } ```
Re: Making one struct work in place of another for function calls.
On Wednesday, 17 April 2024 at 03:13:46 UTC, Liam McGillivray wrote: On Wednesday, 17 April 2024 at 02:39:25 UTC, Paul Backus wrote: This is called [row polymorphism][1], and it does not exist in D. You could approximate it by making `someFunction` a template, and accepting any type `T` that has the necessary members instead of only accepting `typeB`. But this is only possible if you are free to modify the definition of `someFunction`. Is there a way I can replace "`TypeB`" in the function parameters with another symbol, and then define that symbol to accept `TypeB` as an argument, but also accept `TypeA` which would get converted to `TypeB` using a function? I'm willing to make a function template if it's rather simple. Normal template approach would be as simple as: ```d struct TypeA { int x, y; string name; } struct TypeB { float x, y; ubyte[] data; } // Strict version, only allows the named structs float someFunction(S)(S input) if (is(S == TypeA) || is(S == TypeB)) { writefln("input loc: %s,%s", input.x, input.y); return 0; } void main() { someFunction(TypeA(1,1)); someFunction(TypeB(2,2)); } ``` Or you could write the function like: ```d // Permission version, accepts any struct with the required members float someFunction(S)(S input) if (is(S == struct) && isNumeric!(typeof(S.x)) && isNumeric!(typeof(S.y))) { writefln("input loc: %s,%s", input.x, input.y); return 0; } ``` In fact, you don't even necessarily need the template constraints: ```d // It just works... usually float someFunction(S)(S input) { writefln("input loc: %s,%s", input.x, input.y); return 0; } ``` But then you might get (at best) less clear error messages when a wrong type is passed, and (at worst) funny business if someone passes a type that technically satisfies the function behavior but isn't actually a type you expected and is treating those members differently. It's often ideal to have either some type of template constraints, or static ifs/static asserts in the function body so you know what you're dealing with. Another solution, without templates, if you can for instance modify TypeB but not TypeA, is to give TypeB a constructor that takes a TypeA as an argument. ```d struct TypeA { int x, y; string name; } struct TypeB { float x, y; immutable(ubyte)[] data; this(float x, float y) { // We need a constructor here now too this.x = x; this.y = y; } this(TypeA a) { this.x = a.x; this.y = a.y; this.data = cast(immutable(ubyte)[]) a.name; } } float someFunction(TypeB input) { writefln("input loc: %s,%s", input.x, input.y); return 0; } auto someFunction(TypeA input) => someFunction(TypeB(input)); ``` If you cannot modify either struct definition, you could do the conversion by hand in the stub instead. Additionally, if you have many functions and you don't want to write stubs for all of them, you could use mixins to generate them for you like so: ```d float someFunctionUno(TypeB input) { writefln("uno loc: %s,%s", input.x, input.y); return 0; } float someFunctionDos(TypeB input) { writefln("dos loc: %s,%s", input.x, input.y); return 0; } float someFunctionTres(TypeB input) { writefln("tres loc: %s,%s", input.x, input.y); return 0; } // Consider also UDAs, iterating member functions, etc static foreach (sym; "someFunctionUno someFunctionDos someFunctionTres".split) { mixin(format(`auto %s(TypeA input) => %s(TypeB(input));`, sym, sym)); } void main() { someFunctionUno(TypeA(1,1)); someFunctionDos(TypeB(2,2)); } ``` There are yet other ways to do it as well. The solution you'll use will depend on more detailed specifics. In many cases, when working with similar data types and you want the function itself to be as agnostic as possible about what it's dealing with, templates are often the way to go. D's templating/metaprogramming capacities are extremely powerful and flexible. However, it may not necessarily be the right choice if you need to rely on very specific handling of the data types in question and their layouts.
Re: Opinions on iterating a struct to absorb the decoding of a CSV?
On Monday, 1 April 2024 at 04:54:46 UTC, cc wrote: I scoured [Traits](https://dlang.org/spec/traits.html) and [std.traits](https://dlang.org/phobos/std_traits.html) looking for a simple method to tell whether a member was declared as enum but couldn't find one, so if anyone knows a proper way to do it please let me know. Turns out this can be done as part of the panacea that is `is()` statements. ```d static if (is(typeof({enum X = SYM;}))) ```
Re: Opinions on iterating a struct to absorb the decoding of a CSV?
On Thursday, 28 March 2024 at 17:23:39 UTC, Andy Valencia wrote: I wanted a lightweight and simpler CSV decoder. I won't post the whole thing, but basically you instantiate one as: That's pretty much the best way to do it. While `.tupleof` does look kind of hacky, and you could instead iterate using `___traits(allMembers, T)` and `__traits(getMember, T, "symbolname")` which looks more self-documenting, this ends up being more of a pain, because it's going to iterate through everything in the type, including functions, constructors/destructors, aliases, enums, static members, inherited members in classes, etc etc, and it's a plate of spaghetti to sort them all out, plus there are issues with aliasing on top of that. Sometimes you might want to do that of course, but for simple situations like this, `.tupleof` just works. ```d struct Foo { int x = 1; float f = 3.14; string abc = "abc"; string[] xyz; immutable int i; const int c; this(int x) { this.x = x; i = 7; c = 8; } this(float f) { this.f = f; } bool speak() { return false; } bool speak(bool b) { return b; } void toString(scope void delegate(const(char)[]) writer) { /*...*/ } alias X = int; enum E = 3; static enum F = 4; static int y = 5; } void main() { Foo foo; dumpInfo(foo); } void dumpInfo(T)(T t) { import std.traits; static foreach (idx, field; T.tupleof) {{ alias TYPE = typeof(field); enum NAME = field.stringof; writefln("[%s] %s => %s", TYPE.stringof, NAME, t.tupleof[idx]); }} writeln; static foreach (sym; __traits(allMembers, T)) {{ enum bool ISSTATIC = hasStaticMember!(T, sym); static if (ISSTATIC) alias SYM = __traits(getMember, T, sym); else alias SYM = __traits(getMember, t, sym); enum NAME = sym; static if (isType!SYM) { // aliases writefln("(TYPE) %s : %s", NAME, SYM.stringof); } else static if (isFunction!SYM) { alias OVERLOADS = __traits(getOverloads, T, sym); static foreach (idx, FUNC; OVERLOADS) { writefln("(FUNC) %s<%s> : %s", NAME, idx, typeof(FUNC).stringof); writefln("\t%s %s %s", ReturnType!FUNC.stringof, Parameters!FUNC.stringof, ParameterIdentifierTuple!FUNC.stringof); // Useful } } else { alias TYPE = typeof(SYM); // where is isEnum or isManifestConstant? enum bool ISASSIGNABLE = __traits(compiles, {__traits(getMember, t, sym) = __traits(getMember, t, sym);}); enum bool ISASSIGNABLE_IN_CTOR = __traits(compiles, {cast()__traits(getMember, t, sym) = cast()__traits(getMember, t, sym);}); static if (!ISASSIGNABLE && !ISASSIGNABLE_IN_CTOR) { // MAYBE it's an enum. Or something else unassignable. writefln("(ENUM) [%s] %s => %s", TYPE.stringof, NAME, SYM); } else static if (ISSTATIC) { writefln("(STATIC) [%s] %s => %s", TYPE.stringof, NAME, SYM); } else { writefln("[%s] %s => %s", TYPE.stringof, NAME, __traits(getMember, t, sym)); // SYM doesn't work here } } }} } ``` ``` [int] x => 1 [float] f => 3.14 [string] abc => abc [string[]] xyz => [] [immutable(int)] i => 0 [const(int)] c => 0 [int] x => 1 [float] f => 3.14 [string] abc => abc [string[]] xyz => [] [immutable(int)] i => 0 [const(int)] c => 0 (FUNC) __ctor<0> : ref Foo(int x) Foo (int) AliasSeq!("x") (FUNC) __ctor<1> : ref Foo(float f) Foo (float) AliasSeq!("f") (FUNC) speak<0> : bool() bool () () (FUNC) speak<1> : bool(bool b) bool (bool) AliasSeq!("b") (FUNC) toString<0> : void(scope void delegate(const(char)[]) writer) void (scope void delegate(const(char)[])) AliasSeq!("writer") (TYPE) X : int (ENUM) [int] E => 3 (ENUM) [int] F => 4 (STATIC) [int] y => 5 ``` I scoured [Traits](https://dlang.org/spec/traits.html) and [std.traits](https://dlang.org/phobos/std_traits.html) looking for a simple method to tell whether a member was declared as enum but couldn't find one, so if anyone knows a proper way to do it please let me know.
Re: Deriving a struct from another one via template: Easy way to propagate UDAs?
On Thursday, 14 March 2024 at 23:19:37 UTC, Inkrementator wrote: I am trying to derive a struct from another. I want to modify each field such that type of it goes from some T to Nullable!T, preserving all fieldnames and UDAs. This is trivially easy if your types are visible at module level, and mixin is a fine tool for the job. It doesn't work quite so well with [Voldemort types](https://wiki.dlang.org/Voldemort_types). ```d struct MyUDA { int q; } struct Foo { int f; } struct MyStruct { @MyUDA(3) int x; @MyUDA(4) Foo f; @MyUDA(5) @MyUDA(7) string s; } auto generateUDAs(A...)() { string[] udaStrs; static foreach (uda; A) udaStrs ~= "@(" ~ uda.stringof ~ ")"; return udaStrs; } struct Wrapped(S) { static foreach (idx, field; S.tupleof) { //pragma(msg, format(... can be used to preview mixin(format("%s %s %s;", generateUDAs!(__traits(getAttributes, field)).join(' '), Nullable!(typeof(field)).stringof, field.stringof)); } } void main() { MyStruct s; s.x = 3; s.f = Foo(1); s.s = null; Wrapped!MyStruct w; w.x = s.x; w.f = s.f; w.s = s.s; w.x.nullify; w.f.nullify; w.s.nullify; // strings/objects are already nullable though static assert(__traits(getAttributes, w.s) == AliasSeq!(MyUDA(5), MyUDA(7))); } ``` If you absolutely must though, you could do something like ```d enum WrapMixin = q{ struct Wrapped(S) { static foreach (field; S.tupleof) mixin(format("%s %s %s;", generateUDAs!(__traits(getAttributes, field)).join(' '), Nullable!(typeof(field)).stringof, field.stringof)); } }; void main() { struct MyUDA { . struct MyStruct { . mixin(WrapMixin); Wrapped!MyStruct w; } ```
Re: Can a D library have some types determined by the client program?
On Saturday, 9 March 2024 at 22:03:34 UTC, Liam McGillivray wrote: Secondly, I found out that interfaces can't have variables. What!? That's crazy! Why wouldn't they? They totally should. Doesn't this mean that I will need to use getter and setter functions instead of direct access when using interfaces? I don't like this. An interface just defines an interface, a set of method signatures that a class can respond to, and must implement. If you want storage and functionality, you can define a base class. A derived class can inherit from either one base class or one or more interfaces. Or a combination, but multiple inheritance is not a well-liked idea. ```d class Map { int someVar = 3; void someFunc() { // default behavior writeln("hello"); } } class CustomMap!TierType : Map { override void someFunc() { // new behavior writefln("good day %s %s", someVar, TierType.stringof); } } void main() { auto map = new Map; map.someFunc() // hello map = new CustomMap!uint; map.someFunc() // good day 3 uint } ``` In the last line of this code, the variable `map` is still of type `Map` (chosen by `auto` when it received `new Map`, but the actual class object it references is of type `CustomMap!uint`, hence calling a virtual function like `someFunc` calls the derived version instead of the original. Note that functions that take template arguments (not included here) don't necessarily follow this behavior; mixing templated methods and inheritance has some pitfalls.
Re: Can a D library have some types determined by the client program?
On Friday, 8 March 2024 at 06:03:51 UTC, Liam McGillivray wrote: A problem I have is that the 3 classes Map, Tile, and Unit reference each-other. If I turn Map into a template, than it complains about the member variable of Unit declared as `Map map;` without arguments. I change this line to `Map!TileType map;` but this requires that Unit is also turned into a template. If you don't want Unit to be a template, you can just have Map derive from a basic interface or abstract class. You can also have every relevant class share similar templates, you just need to remember to supply the template arguments everywhere. You'll need to think about how much interoperation you want between these classes. Does Unit really need to know what TileType map is using, or can it just trust that when it asks Map to move, Map will handle everything related to tile types? Generally it's best practice to have as much of the inner workings isolated as possible and just provide methods to access functionality. To ease some of the template argument!spaghetti, you could insert aliases into the classes via fully qualified symbol names. Another alternative, if everything is defined on one file, you could wrap everything in a single template, but I don't usually favor this strategy. ```d //version=Interfaced; version=AllTemplated; //version=AllTemplatedAliases; //version=OneTemplate; version(Interfaced) { interface IMap { Unit addNewUnit(); } class Map(TileType) : IMap { Unit[] units; Unit addNewUnit() { auto unit = new Unit(this); units ~= unit; return unit; } } class Unit { IMap map; private this(IMap map) { this.map = map; } } void main() { auto map = new Map!uint; auto unit = map.addNewUnit; } } else version(AllTemplated) { class Map(TileType) { Unit!TileType[] units; auto addNewUnit() { auto unit = new Unit!TileType(this); units ~= unit; return unit; } } class Unit(TileType) { Map!TileType map; private this(Map!TileType map) { this.map = map; } } void main() { auto map = new Map!uint; auto unit = map.addNewUnit; } } else version(AllTemplatedAliases) { class Map(TileType) { alias Unit = mymodule.Unit!TileType; Unit[] units; auto addNewUnit() { auto unit = new Unit(this); units ~= unit; return unit; } } class Unit(TileType) { alias Map = mymodule.Map!TileType; Map map; private this(Map map) { this.map = map; } } void main() { auto map = new Map!uint; auto unit = map.addNewUnit; } } else version(OneTemplate) { template Map(TileType) { class Map { Unit[] units; auto addNewUnit() { auto unit = new Unit(this); units ~= unit; return unit; } } class Unit { Map map; private this(Map map) { this.map = map; } } } void main() { auto map = new Map!uint; auto unit = map.addNewUnit; } } ``` If a given class doesn't really need to know what the template parameters are to the other class it's interacting with, I would avoid defining too many template types everywhere and just use interfaces or abstract parent classes. After changing `class Unit` to `class Unit (TileType), it complains about the line `Unit* occupant;` in Tile. Are you sure you need a pointer here? Class objects in D are already reference-type by default.
Re: Hidden members of Class objects
On Thursday, 7 March 2024 at 00:38:30 UTC, Richard (Rikki) Andrew Cattermole wrote: On 07/03/2024 1:28 PM, Carl Sturtivant wrote: On Wednesday, 6 March 2024 at 23:45:00 UTC, H. S. Teoh wrote: In D, there's a pointer to the vtable and another pointer to a Monitor object (used for synchronized methods). There was talk about getting rid of the Monitor field years ago, but nothing has happened yet. Very interesting: is the monitor field ever touched by compiled D code at any point nowadays? Or is it just vestigial? Yes its opt-in. https://dlang.org/spec/statement.html#synchronized-statement I've stumbled over the Monitor/etc sometimes writing serialization, RPC, LUA etc modules iterating over class members, looking for UDAs, after trying to separate everything out using isFunction/isTemplate/etc, on top of dealing with overload spaghetti, I now just explicitly do something dumb like this to get those edge cases out of the way: ```d static foreach (sym; __traits(allMembers, T)) static if (!["__ctor","__dtor","__xdtor","Monitor","factory"].canFind(sym)) {{ ... ```
Re: Searching for i" in the forum
On Sunday, 25 February 2024 at 01:19:15 UTC, Lysander wrote: On Friday, 23 February 2024 at 23:18:12 UTC, kdevel wrote: How do I search for i" in the forum? I get the following errors: i" -> Error: malformed MATCH expression: [i"] (1) i\" -> Error: malformed MATCH expression: [i\"] (1) 'i"' -> Error: malformed MATCH expression: ['i"'] (1) `i"` -> Error: malformed MATCH expression: [`i"`] (1) "i\"" -> Error: malformed MATCH expression: ["i\""] (1) Use the i\" in the exact phrase box from the advanced search. Advanced search button is on the error page from the malformed match search This doesn't work. It autocorrects to `"i\"` and returns the word/letter `I`, not `i"` letter followed by a doublequote. Looks like some adjustment of the search algorithm may be necessary in light of upcoming interpolated strings.
Re: How can i find my LAN IP Address using std.socket?
On Tuesday, 4 February 2014 at 13:02:26 UTC, TheFlyingFiddle wrote: I'm trying to find my own ip address using std.socket with little success. How would i go about doing this? (It should be a AddressFamily.INET socket) On Windows, you can use the Win32`GetAdaptersInfo`[1] function to get a list of IPv4 adapters and addresses. If you need IPv6 addresses or other more modern features, there is the `GetAdaptersAddresses`[2] function, however it doesn't seem the necessary Windows headers (IPTypes.h / ifdef.h) have been ported to D for this yet. [1] https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersinfo [2] https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses As I attempt to post this, I now see this thread is... 10 years old. Oh well, still relevant I think. ```d import std.string; pragma(lib, `mingw/iphlpapi.lib`); // included with dmd struct Adapter { string name; string desc; struct IPMask { string ip; string mask; } IPMask[] addresses; } Adapter[] getAdapters() { import core.sys.windows.windows; //import core.sys.windows.nspapi; import core.sys.windows.iptypes; import core.sys.windows.iphlpapi; void[] buf; uint size = 0; auto ret = GetAdaptersInfo(null, ); assert(ret == ERROR_BUFFER_OVERFLOW && size > 0, "Expected GetAdaptersInfo to return ERROR_BUFFER_OVERFLOW to query size of buffer"); buf.length = size; ret = GetAdaptersInfo(cast(IP_ADAPTER_INFO*) buf.ptr, ); assert(!ret, "GetAdaptersInfo error"); auto adpt = cast(IP_ADAPTER_INFO*) buf.ptr; Adapter[] adapters; while (adpt) { scope(success) adpt = adpt.Next; Adapter adapter; adapter.name = adpt.AdapterName.fromStringz.idup; adapter.desc = adpt.Description.fromStringz.idup; IP_ADDR_STRING addr = adpt.IpAddressList; auto paddr = while (paddr) { scope(success) paddr = addr.Next; adapter.addresses ~= Adapter.IPMask(paddr.IpAddress.String.fromStringz.idup, paddr.IpMask.String.fromStringz.idup); } adapters ~= adapter; } return adapters; } void main() { import std.stdio; auto adapters = getAdapters(); adapters.writeln; } ```
Re: Generating custom toString for structs
On Thursday, 11 January 2024 at 12:45:45 UTC, cc wrote: I don't use the delegate version personally, but if that's already working for you, may as well stick with it. In retrospect, that delegate version is probably quite a bit better.
Re: Generating custom toString for structs
On Sunday, 7 January 2024 at 09:49:36 UTC, Renato wrote: Hi, I wanted to customize the toString implementation for my structs. So I wrote a mixin for doing that: Alternative format similar to what you already have: ```d import std.format; mixin template ToStringMixin() { void toString(W)(ref W writer) { alias T = typeof(this); writer.formattedWrite("%s(\n", T.stringof); // See also: std.traits.fullyQualifiedName static foreach (idx, field; T.tupleof) { writer.formattedWrite("\t%s: %s\n", T.tupleof[idx].stringof, this.tupleof[idx]); } put(writer, ")"); } } struct Foo { int x, y; string s; mixin ToStringMixin; } void main() { auto foo = Foo(3, 4, "hello"); writeln(foo); } ``` Note however that the templated version of toString(W) can be difficult to debug in some cases as, if it fails to compile, std.format will simply ignore it and not use it while the rest of the program compiles successfully. Any compilation error message can be seen by instead attempting to call the method directly, e.g. something like `auto a = appender!string; foo.toString(a);`. I don't use the delegate version personally, but if that's already working for you, may as well stick with it. If you wanted to avoid including a mixin in all of your structs, another option is to create a generic templated container struct with its own toString: ```d struct ToStringer(T) { T t; // Consider T* t void toString(W)(ref W writer) { //assert(t !is null); writer.formattedWrite("%s(\n", T.stringof); static foreach (idx, field; T.tupleof) { writer.formattedWrite("\t%s: %s\n", T.tupleof[idx].stringof, t.tupleof[idx]); } put(writer, ")"); } } auto ToString(T)(ref T t) { // syntactic sugar return ToStringer!T(t); } struct Foo { int x, y; string s; } void main() { auto foo = Foo(3, 4, "hello"); //writeln(ToStringer!Foo(foo)); writeln(foo.ToString); } ```
Re: Checking path name
On Thursday, 14 December 2023 at 09:38:30 UTC, Joel wrote: On Thursday, 14 December 2023 at 08:47:49 UTC, Anonymouse wrote: On Thursday, 14 December 2023 at 03:58:37 UTC, Joel wrote: https://dlang.org/phobos/std_path.html#isValidPath https://dlang.org/phobos/std_path.html#.isValidFilename Oh, forgot about std.path But what's the difference between path and file name? File name can't contain path separators.
Re: Safer binary reading (or writing) code
On Tuesday, 12 December 2023 at 09:43:39 UTC, Joel wrote: I've got this mixin thing, I think it's less typo-prone. I haven't been able to make it show the variable's name, though. Also, it should be optional whether it prints anything, (it's not hard for me to do that though). ```d // mixin(jread("width")); -> fread(, 1, width.sizeof, bfile); auto jread(string var) => `fread(&`~var~`, 1, `~var~`.sizeof, bfile); writeln("read var=", `~var~`);`; ``` When I need to insert a variable name numerous times into a bit of mixin code, I often use a replace pattern like this: ```d mixin(q{ static struct _aa_$FIELD { KeyType!(typeof(field)) key; ValueType!(typeof(field)) val; } Array!(_aa_$FIELD) $FIELD; }.replace("$FIELD", myVariableName)); ```
Re: Getting all struct members and values with introspection avoiding string mixins
On Sunday, 1 May 2016 at 09:42:37 UTC, ParticlePeter wrote: I am logging arbitrary POD struct types with member names and data: void printStructInfo( T )( T info ) { foreach( i, A; typeof( T.tupleof )) { enum attribName = T.tupleof[i].stringof; writefln( "%s : %s", attribName, mixin( "info." ~ attribName )); } } Is there is some other way to evaluate info.attribName without using string mixins? Cheers, PP If you have `T info`, T.tupleof[n] will always match up with info.tupleof[n]. You can think of `info.tupleof[n]` as being rewritten by the compiler in-place as info.whateverFieldThatIs. You might try this version (note the double {{ }} with static foreach): ```d void printStructInfo( T )( T info ) { static foreach( i, A; info.tupleof ) {{ enum attribName = T.tupleof[i].stringof; writefln( "%s : %s", attribName, info.tupleof[i] ); }} } ``` Be advised that T.tupleof and __traits(allMembers, T) return two different sets of things. allMembers will probably get you a lot of stuff you don't want and will need to write checks to avoid. Using .tupleof is a perfectly acceptable practice.
Re: How to get all modules in a package at CT?
On Thursday, 5 October 2023 at 20:42:26 UTC, mw wrote: On Thursday, 5 October 2023 at 20:07:38 UTC, user1234 wrote: No. Sorry. Generally compile time code cannot interact with the system. To be evaluable at compile time code has to be strongly pure, that is not the case of the function you would need. Otherwise you'd need a new traits for that... but that traits would violate the rule explained before. If you want to iterate the package for modules imported in it, I'm not sure. __traits(allMembers, package) will list names of imported packages but not which modules. static reflection on import decls is broken, that wont work well So how about at runtime? I just want the compiler to help to list them, instead of doing manually. At runtime, simply: ```d foreach (m; ModuleInfo) { writeln(m.name); } ``` However, Walter has hinted that he wants to remove ModuleInfo at some point.
Re: Cool pattern or tragic?
On Friday, 25 August 2023 at 21:00:08 UTC, Guillaume Piolat wrote: The idea is to deliberately mark @system functions that need special scrutiny to use, regardless of their memory-safety. Function that would typically be named `assumeXXX`. ... That way, @safe code will still need to manually @trust them. I basically wanted some kind of functionality similar to this but with regards to the GC. Like some way to annotate a function as @WillAllocate or something, and forbid calling it unless the caller function explicitly acknowledged the allocation (without having to wrap everything in @nogc). Just for fun I experimented with a locking GC that used the struct/dtor model to open/re-lock.
Re: Setting struct as default parameter of a function using struct literal?
On Monday, 11 September 2023 at 17:51:04 UTC, BoQsc wrote: I would like to set function's default struct for a function in a way that it would be visible for the reader to see what options are set. Something like `Options option = {silenceErrors: false}` If the function's defaults will always match the default initializers of the struct itself, ```d struct Options { bool silenceErrors = false; } void someFunction(Options option = Options.init) { writeln(option); } ``` else: ```d struct Options { bool silenceErrors = false; } void someFunction(Options option = Options(silenceErrors: true)) { writeln(option); } ```
Re: Which D compiler is the most maintained and future-proof? [DMD GDC and LDC]
On Monday, 24 July 2023 at 09:29:09 UTC, Richard (Rikki) Andrew Cattermole wrote: There isn't a huge concern with which one you use. Its quite common to use dmd for development, and ldc for release for example. They all share the same frontend, so they really only differ between them by their glue code to the relevant backend and some modules in druntime that are optional. Oh and inline assembly, although there is some compat code in ldc/gdc for dmd style. If dmd dies, so does ldc/gdc basically. Each one sees active development although gdc only has one developer. Ldc keeps up with the dmd releases pretty well. Is there any list of known significant "gotchas" with moving to LDC from DMD? Any unexpected surprises to watch out for or be careful for? I'm thinking of all the "features" of DMD that are now considered verboten by many users (e.g. compiling with -release, disabling of asserts or array bounds checking, etc). Known edge cases of compiler optimization causing different behavior between vendors?
Re: How do I generate `setX` methods for all private mutable variables in a class?
On Monday, 5 June 2023 at 13:57:20 UTC, Ki Rill wrote: How do I generate `setX` methods for all private mutable variables in my class? Do I need to use `__traits`? ```d mixin template GenerateSetters() { static foreach (idx, field; typeof(this).tupleof) static if (__traits(getVisibility,field) == "private") { mixin(q{ void %SETTER(typeof(this.tupleof[idx]) _) { %NAME = _; } } .replace("%NAME", field.stringof) .replace("%SETTER", "set"~toUpper(field.stringof[0..1]) ~ field.stringof[1..$]) ); } } class Rectangle { private Color fillColor; private Color strokeColor; private uint strokeWidth; this(int x, int y) {} mixin GenerateSetters; } void main() { auto rect = new Rectangle(0, 0); rect.setStrokeWidth(4); assert(rect.strokeWidth == 4); } ```
Re: Idiomatic D using GC as a library writer
On Sunday, 4 December 2022 at 09:53:41 UTC, vushu wrote: What are your thoughts about using GC as a library writer? If your program runs, does some stuff, and terminates, use the GC. If your program runs, stays up for a while with user occasionally interacting with it, use the GC. If your program runs, and stays up 24/7 doing things in the background, use the GC. If your program is a game meant to run at 60+fps, and any sudden skip or interrupt is unacceptable, no matter how minor (which it should be), plan carefully about how to manage your game objects, because naive GC instantiation and discarding isn't going to cut it. malloc/free, pre-allocated lists, and other strategies come into play here. In a desperate pinch you can also manually `GC.free` your GC-allocated objects but this is not recommended. The GC can still be used for allocations that are not likely to significantly affect performance every frame (strings, occasional user-generated information requests, first-load data instantiation, Steam avatars, etc) -- but also be even more careful when you start mixing and matching. I find that @nogc is a bit of a false idol though, even in situations where the GC is deliberately being avoided. It simply adds too much pain to trying to make everything compliant, and certain things just plain don't work (amazingly, the non-allocating form of toString can't be @nogc), so I simply avoid it and "be careful" (and/or hook into the GC so I can monitor if an unexpected allocation happens). If you're writing code that's going to run on a space shuttle or life support system, then yeah you might consider the extra effort, but in my use cases it simply fails the cost-benefit analysis. For any strategy, it's still a good idea to have a good understanding of or profile your allocations/deallocations so you're not just spending memory haphazardly or generating excessive collections.
Re: aa.keys, synchronized and shared
On Friday, 11 November 2022 at 01:09:54 UTC, torhu wrote: On Thursday, 10 November 2022 at 21:55:26 UTC, torhu wrote: I'm trying to make a more thread-safe wrapper for AA's: ``` synchronized final class SyncAA(K, V) /// I chose to fix this by just using `synchronized (this)` inside each method instead, for now. Still interested in cleaner solutions, but I guess synchronized/shared is a bit of a rabbit hole... That's about what I ended up with, and just declaring my references __gshared. I don't know what's going on with shared/synchronized but it sounds like it's unfinished and people can't agree on what they're actually supposed to mean. __gshared, it just works. Previous thread: [synchronized/shared associative array .require error](https://forum.dlang.org/post/hcbrgpmdufjgjtxtu...@forum.dlang.org) Also: [synchronized - shared but actually useful](https://forum.dlang.org/thread/drrlgymevccozrqms...@forum.dlang.org) ```d class SyncTable(KEY, VAL) { private VAL[KEY] table; auto opIndexAssign(VAL value, KEY key) { synchronized(this) { return table[key] = value; } } int opApply(int delegate(ref KEY, ref VAL) dg) { synchronized(this) { foreach (key, val; table) { if (dg(key, val)) return 1; } return 0; } } auto opBinaryRight(string op)(KEY key) if (op == "in") { synchronized(this) { return key in table; } } auto opDispatch(string s, SA...)(SA sargs) { synchronized(this) { static if (SA.length == 0) { mixin(format("return table.%s;", s)); } else { mixin(format("return table.%s(%s);", s, sargs.stringof[6 .. $-1])); // tuple(_param_0) } } } } ``` With synchronized on the class, I had to do something like: ```d synchronized class SyncTable(KEY, VAL) { // Anything that mutates must reassign unshared back to table! auto opIndexAssign(VAL value, KEY key) { auto unshared = cast(T) table; unshared[key] = value; table = cast(shared) unshared; return value; } auto require(KEY key) { auto unshared = cast(T) table; auto r = unshared.require(key); table = cast(shared) unshared; return r; } /* ... */ } ``` and it just doesn't feel right. For mutexes without synchronized, there's also: ```d struct Lock { private shared Mutex _mtx; this(shared Mutex mtx) { _mtx = mtx; _mtx.lock(); } this(this) @disable; ~this() { if (_mtx) _mtx.unlock(); _mtx = null; } } class SyncTable(KEY, VAL) { private VAL[KEY] table; shared Mutex mtx; this() { mtx = new shared Mutex; } auto opIndexAssign(VAL value, KEY key) { auto lock = Lock(mtx); return table[key] = value; } /* ... */ } ```
DConf '22: No-Allocated 0-terminated path strings
Catching up on the DConf '22 videos, really enjoyed the tricks Walter presents here for no-allocation strings: [DConf '22: Strawberries and Cream aka Delightful Emergent Properties of D -- Walter Bright](https://www.youtube.com/watch?v=iuP-AWUyjp8) In the Q segment, the first question asked whether the filename in the path example needs memory allocation to be passed to C, and is told it does, however the two methods presented can be easily combined to provide no-allocation 0-terminated strings from `chain()`ed paths by passing an `InputRange` rather than a `const(char)` to `toCStringThen`: ```d //version=AllowMalloc; auto toCStringThen(alias dg, Range)(Range src) /*nothrow*/ if (isInputRange!Range && !isInfinite!Range) { const len = src.walkLength; char[512] small = void; version(AllowMalloc) { import dmd.common.string : SmallBuffer; auto sb = SmallBuffer!char(len + 1, small[]); scope ptr = sb[]; } else { enforce(len < small.length, format!"C string buffer overflow (%s >= %s)"(len, small.length)); scope ptr = small[]; } size_t i = 0; foreach (char c; src) ptr[i++] = c; ptr[len] = '\0'; return dg(ptr); } void main() { string path = "include/"; string name = "file"; string ext = ".ext"; auto filename = chain(path, name, ext); filename.writeln; filename.byChar.toCStringThen!( (str) => printf("printf: {%s}\n", str.ptr) ); } ``` May need to be cleaned up for character types and needs to iterate twice if allocations are going to be allowed, and walkLength/chain()'s range functions aren't nothrow as far as I can tell. But otherwise thought this was kind of neat, just posting it here in case anyone else finds it handy.
Does the GC prioritize same-class when looking for things to free?
Why is Foo never deallocated here? (`DMD32 D Compiler v2.099.0-dirty` win64) ```d class Foo { string s; static size_t count, alloced, dealloced; this() { "+Foo".writeln; count++; alloced++; } ~this() { "~Foo".writeln; count--; dealloced++; } } class Bar { string s; static size_t count, alloced, dealloced; this() { count++; alloced++; } ~this() { count--; dealloced++; } } void main() { static assert(__traits(classInstanceSize, Foo) == __traits(classInstanceSize, Bar)); GC.collect(); writeln(GC.stats.usedSize, " START"); { new Foo; } foreach (i; 0 .. 4_000_000) { new Bar; if (Foo.dealloced) break; } writeln(GC.stats.usedSize); writeln("Foo: ", Foo.count); writefln("Bar: %,d (%,d - %,d)", Bar.count, Bar.alloced, Bar.dealloced); GC.collect(); GC.minimize(); writeln(GC.stats.usedSize, " END"); ``` ``` 0 START +Foo 89632 Foo: 1 Bar: 2,800 (4,000,000 - 3,997,200) 64 END ~Foo ```
Re: synchronized/shared associative array .require error
On Saturday, 3 September 2022 at 14:37:16 UTC, Steven Schveighoffer wrote: On 9/2/22 3:15 PM, cc wrote: Tried casting away shared as a workaround but I assume that will cause some kind of TLS catastrophe. I think it will be fine, but you may have an issue. You are returning a non-shared `VAL`, but your class is `shared`, which means `table`, and all the `VAL` and `KEY` inside must also be `shared`. If you cast away `shared` you have to put it back upon return. TLS should not be involved here at all, so there is no problem there. -Steve Alright, so this is safe then? ```d alias VAL[KEY] T; auto require(KEY key) { auto unsharedT = cast(T) table; auto r = unsharedT.require(key); table = cast(shared) unsharedT; return cast(shared) r; } ``` Was a bit surprised to see mutating `unsharedT` left `table` unchanged and needed reassigning.
synchronized/shared associative array .require error
```d synchronized class SyncTable(KEY, VAL) { private VAL[KEY] table; auto require(KEY key) { return table.require(key); } } auto table = new shared SyncTable!(string, string); table.require("abc"); ``` Fails to compile: ``` // Error: none of the overloads of template `object.require` are callable using argument types `!()(shared(string[string]), string)` ``` Tried casting away shared as a workaround but I assume that will cause some kind of TLS catastrophe.
Re: How to call a function from a dll created with d ?
On Sunday, 3 July 2022 at 09:43:20 UTC, frame wrote: app.d: ```d module app; import dimedll; import std.stdio; import std.stdio : log = writeln; pragma(lib, "dimedll.lib"); void main() { log("Lets build our own ime"); testFunc(); } ``` You should be able to change contents in the DLL and run the executable wihtout re-compiling (the library file should be round ~2kB). PS: ddemangle just waits for your input. You copy in the mangled symbol like `__D7dimedll12__ModuleInfoZ` and press enter ;-) Does importing dimedll into app.d properly NOT link in the functions that are exported to the DLL? When I tried something similar with dmd, I had to create a .di file containing just stubs, otherwise it looked like it was ignoring the DLL and compiling in an additional copy of each fuction.
getSymbolsByUDA in constructor/member functions
```d import std.traits; class XML {} class Def { @XML { int x; int y; } int z; this() { static foreach (sym; getSymbolsByUDA!(Def, XML)) { } } } void main() { auto def = new Def; } ``` ``` test.d(12): Error: value of `this` is not known at compile time test.d(12): Error: value of `this` is not known at compile time ``` Why doesn't this work? There is nothing in the foreach body. ```d alias ALL = getSymbolsByUDA!(Def, XML); pragma(msg, ALL.stringof); ``` reports `tuple(this.x, this.y)`. Why is `this.` added?
Re: How to call destroy() in @nogc?
On Tuesday, 24 May 2022 at 02:55:06 UTC, Tejas wrote: On Tuesday, 24 May 2022 at 02:29:38 UTC, cc wrote: ```d import core.memory; import core.stdc.stdlib : malloc, free; import core.lifetime : emplace; [...] FWIW your code will compile if you add `extern(C++)` to `Foo` Interesting, thanks. I noticed something similar when trying to call malloc in a pure function... std.internal.memory: ```d extern (C) @nogc nothrow pure private { pragma(mangle, "malloc") void* fakePureMalloc(size_t) @safe; pragma(mangle, "calloc") void* fakePureCalloc(size_t nmemb, size_t size) @safe; pragma(mangle, "realloc") void* fakePureRealloc(return scope void* ptr, size_t size) @system; } ```
How to call destroy() in @nogc?
```d import core.memory; import core.stdc.stdlib : malloc, free; import core.lifetime : emplace; T NEW(T, Args...)(auto ref Args args) /*@nogc*/ if (is(T == class)) { enum size = __traits(classInstanceSize, T); void* mem = malloc(size); scope(failure) free(mem); return mem !is null ? emplace!T(mem[0..size], args) : null; } void FREE(T)(ref T obj) @nogc if (is(T == class)) { auto mem = cast(void*) obj; scope(exit) free(mem); destroy(obj); obj = null; } class Foo { ~this() @nogc {} } void main() { auto foo = NEW!Foo; FREE(foo); } ``` ``` Error: `@nogc` function `nogctest.FREE!(Foo).FREE` cannot call non-@nogc function `object.destroy!(true, Foo).destroy` ``` Is this not currently possible? Found this thread: https://forum.dlang.org/thread/zanuuhzmqxljadcex...@forum.dlang.org?page=1 is it still unresolved?
Re: What are (were) the most difficult parts of D?
On Monday, 16 May 2022 at 15:08:15 UTC, H. S. Teoh wrote: If you find yourself having to cast to/from immutable, you're using it wrong. I clearly was, which is why I'm not using it anymore. The question was "What are you stuck at? What was the most difficult features to understand? etc.", so I listed the things that tripped me up in my early time with D. I assumed the context of this was collecting useful information for, say, understanding what newcomers' sticking points are and maybe thinking how to make D more accessible to them. Maybe this wasn't the intent, but this kind of comes across more as a lecture on how everything I was doing wrong is my own fault even when I've already stated I'm *not doing those things anymore*. I write D programs that process input files all the time, including stuffing data into AAs and what-not, and it Just Works(tm). Of course it just works, why wouldn't it? But not once did I bother with immutable (why should I?). Because the documentation crams it down your throat. Or at least it did, along with the early blog/wiki posts that were the only source of D information I could find back at the time. And yes, I pored over that page on the differences between const and immutable years ago, which sang immutable's praises at length, how it was D's greatest innovation to set it apart from C++, and implied it should be slapped on literally everything that never changes and how great this was for multithreading, hence why I (formerly) felt the need to try and define all my persistent definitions as immutable. Now I slap __gshared on everything and just let it go. For anything performance-related, I don't even look at dmd, I use LDC all the way. DMD is only useful for fast compile-run-debug cycle, I don't even look at performance numbers for DMD-produced executables, it doesn't mean anything to me. According to the dlang.org wiki entry for LDC: druntime/Phobos support is most likely lacking (and probably requires a new version predefined by the compiler). So I'm not touching it for now. Don't have time to investigate a completely new compiler and track down incompatibilities when DMD works and I've been invested in it. The fact that LDC is more performant than DMD surely not does imply attempting to optimize DMD-compiled programs is futile. My use of immutable was based in part on a (mistaken) assumption that this was a recommended best practice for multithreading safety and performance. Just make things private and use getters/setters to control access. Like I said, if you find yourself writing lots of casts Equally irritating. Direct access is far less annoying to write. Yes, I could use mixins to automate some of this but it still uglifies the code even more to no great advantage for my purposes. Getters/setters have always felt relevant only to large team environments, when you can't count on another developer knowing certain things aren't meant to be touched. For simple self-protection, I like C#'s "readonly" keyword, as I said. Statement of opinion. I wish D had something similarly painless to use, but it doesn't, so I'm out of luck. I just direct access and try to not make mistakes instead. Why would you want to force deterministic memory management onto GC-allocated objects? Just use malloc/free (or whatever else Because when I first got into D this was *not made clear*. The GC was sold so heavily and every single non-GC approach to memory management was made to look like, at best, a crude circumvention, and at worst a pariah. In C++ I could new/delete, in ObjC I had alloc/autorelease, D had new, and also delete at the time, which was not adequately explained that it pretty much did nothing, and even then it (and its hacky replacement __delete) were bugged anyway. Perhaps this was my own ignorance, fair enough. NOW I already use malloc/free for everything important. But is this helpful to future newcomers? Wait till they screw up, don't understand why, then tell them after the fact they were doing it wrong, if they're still around by that point? To this day, as your post demonstrates, the GC is still extolled as the correct solution to 99% of problems, with alternatives only grudgingly admitted to after a person reports running into problems. On top of this, at the time I got into D, the GC just plain DIDN'T work for arbitrary chunks of data unless you carefully zeroed them out. I could easily write trivial programs to read a binary file's raw data into an array of ubyte[], let it go out of scope without any escaped pointers, and crash with out of memory as the loop cheerfully ate up 8+ GB. The move to 64-bit and whatever bugfixes may have happened in the past years helped and fortunately everything "Just Works" NOW. But back then, it didn't. So when on top of this my programs started having disastrous performance issues due to GC collections because the
Re: What are (were) the most difficult parts of D?
On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote: What are you stuck at? What was the most difficult features to understand? etc. To make it more meaningful, what is your experience with other languages? Ali Immutability. Ended up having to do so many hundreds of casts to and from immutable(whatever) the amount of mental strain greatly exceeded whatever benefits the entire concept is supposed to offer. Safety? Performance, in a future compiler version? I don't know where it's at right now. But you'd think I could do something like load some data from disk, craft a few objects, mark them as immutable, and shove them in an array or associative array without it being a nightmare, but it isn't. Or, having an otherwise mutable class with a member that references an immutable class, but can change which immutable instance it's referencing, without having to cast away the immutability of the thing I'm trying to protect in the first place. So I just stopped doing it, and simply rely on the "just don't make mistakes" practice to avoid writing to things that shouldn't be written to now. C#'s concept of marking a class member as "readonly" feels a lot more like what I was hoping to get. It doesn't complain at me when I return something that's readonly and the receiving destination isn't expecting it to be readonly, and also I have more free reign over what I can do to it during the constructor phase before it becomes hands-off. Things look a lot cleaner without another set of parentheses around every variable too. On another topic, the lack of a good "delete" keyword doing what one would expect, when there's a perfectly good "new" without its matching existential companion. This, and the ways around it, have already been discussed to death though, but banging my head over trying to force deterministic memory management into the GC-controlled D universe did take its toll on a good year or two of productivity.
Re: How to use destroy and free.
The MemUtils package offers a `ScopedPool` utility that seems interesting. It isn't well documented however so I have no idea if it actually works like I expect. I presume this would work something akin to a VM memory snapshot/rollback for the GC? It would be pretty handy for some scenarios, say a serialization library. You specify a snapshot point (add a pool to the stack?), incur all your GC allocations necessary for generating the structure of your serialized data (which go into the pool instead of the GC proper?), then you write it to disk and pop the stack, effectively rolling back to the original memory state of your program's GC. As long as you make sure not to leak anything allocated within that phase, seems like a good deal. https://code.dlang.org/packages/memutils
Re: How to use destroy and free.
On Wednesday, 4 May 2022 at 05:37:49 UTC, forkit wrote: inscope int[] i = new int[1]; You often see the "here's an array of ints that exists only in one scope to do one thing, should we leave it floating in memory or destroy it immediately?" as examples for these GC discussions. Not to steal OP's thread and whatever particular needs he's trying to achive, but hopefully provide another use case: I write games, and performance is the number one priority, and I stumbled heavily with the GC when I first began writing them in D. Naively, I began writing the same types of engines I always did, and probably thinking with a C/C++ mentality of "just delete anything you create", with a game loop that involved potentially hundreds of entities coming into existence or being destroyed every frame, in >=60 frame per second applications. The results were predictably disastrous, with collections running every couple seconds, causing noticeable stutters in the performance and disruptions of the game timing. It might have been my fault, but it really, really turned me off from the GC completely for a good long while. I don't know what types of programs the majority of the D community writes. My perception, probably biased, was that D's documentation, tours, and blogs leaned heavily towards "run once, do a thing, and quit" applications that have no problem leaving every single thing up to the GC, and this wasn't necessarily a good fit for programs that run for hours at a time and are constantly changing state. Notably, an early wiki post people with GC issues were directed to revolved heavily around tweaks and suggestions to work within the GC, with the malloc approach treated as a last-resort afterthought. Pre-allocating lists wasn't a good option as I didn't want to set an upper limit on the number of potential entities. The emergency fix at the time was inserting GC.free to forcibly deallocate things. Ultimately, the obvious *correct* answer is just using the malloc/emplace/free combo, but I'm just disappointed with how ugly and hacky this looks, at least until they've been wrapped in some nice NEW()/DELETE() templates. ```d auto foo = new Foo; delete foo; // R.I.P. ``` ```d import core.stdc.stdlib : malloc, free; import core.lifetime : emplace; auto foo = cast(Foo) malloc(__traits(classInstanceSize, Foo)); emplace!Foo(foo); destroy(foo); free(cast(void*) foo); ``` Can you honestly say the second one looks as clean and proper as the first? Maybe it's a purely cosmetic quibble, but one feels like I'm using the language correctly (I'm not!), and the other feels like I'm breaking it (I'm not!). I still use the GC for simple niceties like computations and searches that don't occur every frame, though even then I've started leaning more towards std.container.array and similar solutions; additionally, if something IS going to stay in memory forever (once-loaded data files, etc), why put it in the GC at all, if that's just going to increase the area that needs to be scanned when a collection finally does occur? I'd like to experiment more with reference counting in the future, but since it's just kind of a "cool trick" in D currently involving wrapping references in structs, there are some hangups. Consider for example: ```d import std.container.array; struct RC(T : Object) { T obj; // insert postblit and refcounting magic here } class Farm { Array!(RC!Animal) animals; } class Animal { RC!Farm myFarm; // Error: struct `test.RC(T : Object)` recursive template expansion } ``` Logically, this can lead to leaked memory, as a Farm and Animal that both reference each other going out of scope simultaneously would never get deallocated. But, something like this ought to at least *compile* (it doesn't), and leave it up to the programmer to handle logical leak problems, or so my thinking goes at least. I also really hate having to prepend RC! or RefCounted! to *everything*, unless I wrap it all in prettier aliases.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 17:05:09 UTC, H. S. Teoh wrote: Oops, sorry, I made a mistake. The definition of Serializable should be: class Serializable(Base, Derived = Object) : Base {} There we go, works with this, now I get what it's trying to do: ```d class Serializable(Base, Derived = Object) : Derived { ``` What's the purpose of the `static struct Proxy`? The `static this()` seems to work without being enclosed in a structure.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 16:51:33 UTC, H. S. Teoh wrote: On Tue, May 03, 2022 at 04:38:23PM +, cc via Digitalmars-d-learn wrote: On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: >class Base : Serializable!(Base) { ... } >class Derived : Serializable!(Base, Derived) { ... } This is really interesting syntax, I'm surprised that works! https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern It's a bit counterintuitive at first, but once you "get" how it works, it's an extremely powerful technique for leveraging D's compile-time introspection capabilities. And translating compile-time information into runtime using static this(). ;-) T Hm although I am having trouble with that particular implementation: ```d class Base : Serializable!(Base) {} class Derived : Serializable!(Base, Derived) {} class Serializable(Base, Derived = Base) : Base {} ``` ``` Error: class `test.Base` circular inheritance Error: template instance `test.Serializable!(Base, Base)` error instantiating ```
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 15:08:53 UTC, H. S. Teoh wrote: class Base : Serializable!(Base) { ... } class Derived : Serializable!(Base, Derived) { ... } This is really interesting syntax, I'm surprised that works!
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 10:48:53 UTC, bauss wrote: Object.factory calls TypeInfo_Class.find which just loops through ModuleInfo and then looks if any of the entries in localClasses has a name that matches. Afterwards it calls the create function on the TypeInfo_Class which of course isn't "generic" by any means. This is where compile-time has its limits compared to runtime type creation, because templates only live during compile-time then it isn't really that easy to do something like this, where it would be trivial in other languages like C#. On Tuesday, 3 May 2022 at 12:46:56 UTC, Adam D Ruppe wrote: On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: something I can pass to `Object.factory`. Object.factory is useless and will hopefully be removed someday. Instead, make your own factory registration function. Put a static constructor in the class which appends a factory delegate to an array or something you can use later. Then you can use your own thing to construct registered objects. Yeah, that's unfortunate. Actually I was already doing something similar for serialization/encoding to get the true type of an object (making sure `Animal an = new Cat();` encodes a Cat and not an Animal), took me a second to put two and two together and realize I could just instantiate objects via new that way instead of calling Object.factory. At the moment I try to register as many relevant symbols as I can automatically when encoding is called for a given object, such as: ```d private mixin template RegisterModule(alias MOD) { void RegisterModule() { static foreach (SYM; getSymbolsByUDA!(MOD, Coder)) { static if (is(SYM == class)) { RegisterSerializer!SYM(); } } } } private static void[0][string] registeredModules; private void registerModules(T)() { enum string MODULENAME = moduleName!T; if (MODULENAME !in registeredModules) { registeredModules.require(MODULENAME); mixin("import "~MODULENAME~";"); mixin("mixin RegisterModule!"~MODULENAME~";"); RegisterModule(); } } IPtr encode(T)(T obj) { registerModules!T; ... } ``` I'll have to get a little more creative for registering templated classes then, something like this works: ```d static void RegisterSerializer(alias SYM)(string runtimeName = null) { enum sym = fullyQualifiedName!SYM; if (sym !in serialTypes) { auto st = new SerialType!SYM; serialTypes[sym] = st; if (runtimeName.length && runtimeName !in serialTypes) serialTypes[runtimeName] = st; } } static void RegisterSerializer(T : Object)(T obj) { RegisterSerializer!T(typeid(obj).name); } ``` but I'd rather not have to instantiate an actual object just to get its typeid().name, I suppose I can just manually construct it from the fullyQualifiedName inserting the parenthesis and appended portion so it matches.
Re: How to get compatible symbol names and runtime typeid names for templated classes?
On Tuesday, 3 May 2022 at 09:42:45 UTC, cc wrote: Given a runtime typeid, how can I get the equivalent fullyQualifiedName without attempting to mangle the string myself manually? e.g. something I can pass to `Object.factory`. Actually, looking at this further, does Object.factory even support templates? I'm getting null returned from any attempt to instantiate a templated classname.
How to get compatible symbol names and runtime typeid names for templated classes?
This produces compatible strings between symbol and runtime type: ```d class Foo {} void main() { alias Foo F; writeln(fullyQualifiedName!F); auto f = new F; writeln(typeid(f).name); } ``` ``` test.Foo test.Foo ``` But if the class is a template, the strings different: ```d class Foo(bool b) {} void main() { alias Foo!true F; writeln(fullyQualifiedName!F); auto f = new F; writeln(typeid(f).name); } ``` ``` test.Foo!(true) test.Foo!true.Foo ``` Given a runtime typeid, how can I get the equivalent fullyQualifiedName without attempting to mangle the string myself manually? e.g. something I can pass to `Object.factory`.
Re: Reference counting example
On Tuesday, 26 April 2022 at 22:16:01 UTC, cc wrote: Test application: I should point out that all this stuff with saving refcounted things to arrays and so on is extremely untested and experimental One problem I'm seeing is the inability for a refcounted class to pass itself to another function, since the class internals don't see the struct wrapper.. you can pass the naked object reference itself, and hope the reference doesn't get saved otherwise there's your dangling pointer, but then you also have the problem of inconsistent method declarations, with some things taking Foo and others taking RefCounted!Foo etc... Every night I pray for a `refcounted` keyword. Wouldn't something like `auto foo = new refcount Foo();` be nice? Then every class that deals with the objects could continue to be allocator-agnostic... definitely not a trivial change though.
Re: A template construct like using()
On Tuesday, 26 April 2022 at 21:33:43 UTC, Chris Katko wrote: I swear I asked something like this before years ago but it doesn't show up in my previous forum posts. I'm looking for a construct that mimics using(var)/with(var) ```d void draw_with(bitmap* drawb, void delegate() dg) { set_target_bitmap(drawb); dg(); set_target_bitmap(original_target); } bitmap* b; draw_with(b, { draw_pixel(red, 16, 16); }); ``` If your draw code doesn't depend on any scoped state you can use `function()` instead of `delegate()` to save a GC call.
Re: Reference counting example
On Tuesday, 26 April 2022 at 06:55:34 UTC, Alain De Vos wrote: Can someone provide a simple/very simple reference counting or refcounted example i can understand. Thanks. I've been playing around with the automem[1] library's RefCounted feature as we speak, it seems to fit my needs more than std.typecons which doesn't quite do what I want. I did have to make some changes to the library though to allow for inheritance and manually releasing (below). It's pretty fun so far so I'm looking forward to trying it in some other projects like a non-GC XML library. [1] https://github.com/atilaneves/automem Test application: ```d import std.stdio; import core.memory; import util.array; // ARRAY Custom wrapper for std.container.array // The vector/array library provided with automem does NOT properly destroy array elements // so we'll use std.container.array instead import std.experimental.allocator.mallocator; import automem; alias RC(T) = RefCounted!(T, Mallocator); // Optional default constructor workaround auto RCREATE(T, Args...)(auto ref Args args) { return RC!T.create(args); } class Farm { ARRAY!(RC!Cow) animals; //this() {} this(int) { writeln("[Farm]"); } ~this() { writeln("[~Farm]"); animals.clear(); writeln("[/Farm]"); } void pet(RC!Animal animal) { writefln("Farm: The %s says...", animal); animal.speak; } } class Animal { void speak() { writeln("Animal: ???"); } } class Cow : Animal { ARRAY!(RC!Animal) friends; // Amazingly, this works, as long as the array elem type is NOT the same as RC!(this class) // otherwise we get a forwarding error int x; this() { writefln("[Cow]"); } this(int x) { this.x = x; writefln("[Cow %s]", x); } ~this() { writefln("[/Cow %s]", x); } override void speak() { writefln("Cow#%s: Moo.", x); } } void main() { auto used = GC.stats.usedSize; scope(exit) assert(GC.stats.usedSize == used); // GC is not touched! { assert(RCREATE!Cow.x == 0); assert(RCREATE!Cow(99).x == 99); } RC!Animal other; auto farm = RC!Farm(1); { auto cow = RC!Cow(1); farm.animals ~= cow; farm.animals ~= RC!Cow(2); other = farm.animals[1]; auto cowGoesOutOfScope = RC!Cow(70); } writeln("out, should have seen Cow#70's dtor"); farm.animals[0] = farm.animals[1]; writeln("animals[0] (Cow#1) just got overwritten so we should have seen its dtor"); farm.animals ~= RC!Cow(3); farm.pet(other); other = null; farm = null; writeln("done"); } ``` Output: ``` [Cow] [/Cow 0] [Cow 99] [/Cow 99] [Farm] [Cow 1] [Cow 2] [Cow 70] [/Cow 70] out, should have seen Cow#70's dtor [/Cow 1] animals[0] (Cow#1) just got overwritten so we should have seen its dtor [Cow 3] Farm: The memtest.Cow says... Cow#2: Moo. [~Farm] [/Cow 2] [/Cow 3] [/Farm] done ``` I added the following functions to automem `ref_counted.d`: ```d // static .create method to allow use of class's default constructor if desired static if (isGlobal && is(Type == class) && __traits(compiles, new Type())) { static auto create(Args...)(auto ref Args args) { typeof(this) obj; obj.makeObject!args(); return obj; } } // allow instantiation or assignment from derived classes if the Allocator is the same this(U)(ref RefCounted!(U,Allocator) rhs) if (is(U == class) && !is(U == Type)) { _impl = cast(typeof(_impl)) rhs._impl; if(_impl !is null) inc; } void opAssign(U : Type)(ref RefCounted!(U,Allocator) other) if (is(U == class) && !is(U == Type)) { //if (_impl == other._impl) return; if (_impl._rawMemory.ptr == other._impl._rawMemory.ptr) return; if(_impl !is null) release; static if(!isGlobal) _allocator = other._allocator; _impl = cast(typeof(_impl)) other._impl; if(_impl !is null) inc; } // Allow assigning null to manually release payload void opAssign(typeof(null)) { if(_impl !is null) release; _impl = null; } ```
Re: Assigning to array of structs with custom constructor
On Monday, 25 April 2022 at 15:23:12 UTC, Ali Çehreli wrote: auto arr = iota(10).map!(i => Foo(i.text)).array; On Monday, 25 April 2022 at 16:11:47 UTC, rassoc wrote: Foo[] arr = ["abc", "def", "ghi"].map!Foo.array; Ahh that'll do it alright, thanks
Get UDAs of self's declaration as a member?
Hard to word this question right, but is it possible to get the UDAs assigned to a class/structure's member variable declaration, within that variable's definition? e.g. ```d import std.stdio; import std.traits; enum SPECIAL; struct Foo { void foo() { static if (hasUDA!(typeof(this), SPECIAL)) writeln("special"); else writeln("not special"); } } struct Bar { @SPECIAL Foo foo; } void main() { Foo foo; foo.foo; Bar bar; bar.foo.foo; } ``` This doesn't work of course, `@SPECIAL` isn't applied to `struct Foo` itself so no UDA is found by `hasUDA!Foo`. Without iterating Bar directly, is there some way to detect *within* Foo's member functions, that the Foo being called is declared with `@SPECIAL` inside its parent structure?
Re: Linked list, printing looks destructive.
On Monday, 25 April 2022 at 01:40:01 UTC, Alain De Vod wrote: Following program is a single linked list. We expect as output 1 2 3 1 2 3 But the output is only 1 2 3 ``` If you don't need List to be treated as a true range, but just want to iterate, a simple way to do this is with opApply: https://tour.dlang.org/tour/en/gems/opdispatch-opapply ```d import std.stdio: write,writeln; import std.range: empty,popFront,front; struct Node { int element; Node * next; } class List { Node * root=null; this(int[] AR){foreach(i ; AR)pushfront(i);} bool empty() const {return !root;} /*void popFront() {root=root.next;} float front() const {return root.element;}*/ void pushfront(int element) { Node * newnode=new Node(); newnode.element=element; newnode.next=root; root=newnode; } int opApply(int delegate(typeof(Node.element)) dg) { Node* current = root; while (current) { if (dg(current.element)) return 1; // stop iteration if the foreach body asks to break current = current.next; } return 0; } }//List void main(){ List l=new List([3,2,1]); foreach(element; l) writeln(element); foreach(element; l) writeln(element); } // 1 2 3 1 2 3 ```
Re: Assigning to array of structs with custom constructor
On Monday, 25 April 2022 at 15:13:51 UTC, Stanislav Blinov wrote: Make it explicit: ```d Foo[] foos = [Foo("a")]; ``` There's that too, but I still have to iterate manually. e.g.: ```d string[] ss = loadABunchOfStringsFromSomewhere(); //Foo[] foos = ss; //error Foo[] foos; foos.reserve(ss.length); foreach (s; ss) foos ~= Foo(s); ``` Was just hoping there was a way to streamline it within the struct definition.
Re: Assigning to array of structs with custom constructor
On Monday, 25 April 2022 at 15:00:13 UTC, Alain De Vos wrote: Not really an answer but this works, ``` void main(){ Foo foo = "a"; Foo[] foos; foos ~=foo; }% ``` Right, I can append individual elements, but can't assign or append a slice of a type that can be individually cast to the struct.
Assigning to array of structs with custom constructor
```d struct Foo { string s; this(string s) { this.s = s; } } Foo foo = "a"; Foo[] foos = ["a"]; // Error: cannot implicitly convert expression `["a"]` of type `string[]` to `Foo[]` Foo[] foos = cast(Foo[]) ["a"]; // Error: e2ir: cannot cast `"a"` of type `string` to type `Foo` ``` Was there a way to do this? I thought I recalled seeing something like this before, but I can't seem to find it.
Re: Static struct initialization syntax behavior & it being disabled upon adding a constructor
On Monday, 18 April 2022 at 10:26:16 UTC, HuskyNator wrote: On a sidenote, I'm surprised D did not choose 0 as the default floating value. Doesn't almost every language do this? I understand the thinking behind it, but when the type one uses in a template influences the behavior of the code, that seems like a pretty big red flag to me. (Any non-floating type defaults to 0, but using floats/doubles suddenly introduces NaN, surely I'm not the only one that sees a problem with this ) Especially when it's basically a standard 0 is used for this. Sorry for the rant. I agree, it's a hiccup. I have at times intentionally initialized a float as NaN so that I can identify later whether an appropriate value has been assigned, but I've never seen the need to have this be the default behavior when integer types always init to 0 (more specifically, init to a MODIFYABLE value). In game design I have tons upon tons of floats that all [should] start initialized to zero. I can add 4 to a declared but not-assigned-to int and it'll be 4, a float remains NaN. Having to manually declare appropriate init values to each one doesn't aid me in detecting "bugs". If I had an int that was supposed to default to 10 instead of 0 it would still be a bug if I forgot to specify that, tripping me up for falsely assuming floats would start at 0 doesn't aid my workflow in any way. The whole "you should pay more attention to what you're initializing, o buggy programmer you" philosophy seems like something that should be reserved for pointers and reference types, not basic numeric data. It's probably set in stone by this point though and too late to change. Ten years ago, almost to the day: https://forum.dlang.org/thread/thsjtreegdwcgbazh...@forum.dlang.org The reasoning still feels flimsy and stubborn.
Re: Static struct initialization syntax behavior & it being disabled upon adding a constructor
On Monday, 18 April 2022 at 03:21:30 UTC, H. S. Teoh wrote: Structs in D ought to be treated like "glorified ints", as Andrei puts it. If you need complex ctors and complex methods, that's a sign you should be using a class instead. Unless you're having a nice quiet get-together with friends, and you don't want to invite the GC, the biggest loudest party animal on the block. Phobos's RefCounted seems to stretch the definition of "glorified ints"..
Re: Importing version identifiers from another file?
Another option for this was suggested here: https://forum.dlang.org/post/qbvgboihhwcuqglyg...@forum.dlang.org On Wednesday, 12 February 2020 at 09:28:15 UTC, Simen Kjærås wrote: 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
Re: Printing a quoted string
On Tuesday, 22 March 2022 at 07:18:00 UTC, cc wrote: On Sunday, 20 March 2022 at 09:42:44 UTC, Caten wrote: Hi, I also need a function to "unquote" string, like this: ```d assert(unquote(`\n`)=="\n"); ``` Is there a way to do that? I rolled my own for that recently: ```d string dequote(string str) @safe pure { if (str.length < 2) return str; if ((str[0] == '"' || str[0] == '\'' || str[0] == '`') && str[$-1] == str[0]) { return str[1 .. $-1]; } return str; } ``` Oops, I misread what you were asking for. Was thinking quotes like quotation marks, not backslashes.
Re: Printing a quoted string
On Sunday, 20 March 2022 at 09:42:44 UTC, Caten wrote: Hi, I also need a function to "unquote" string, like this: ```d assert(unquote(`\n`)=="\n"); ``` Is there a way to do that? I rolled my own for that recently: ```d string dequote(string str) @safe pure { if (str.length < 2) return str; if ((str[0] == '"' || str[0] == '\'' || str[0] == '`') && str[$-1] == str[0]) { return str[1 .. $-1]; } return str; } ```
Determining function template from runtime type: better ideas?
Sorry for the fairly lengthy post. I'm wondering if there are any suggested good practices in place for calling templated functions using the runtime type of an object, e.g. what `typeid(object)` returns. Consider the following situation: ```d class Person { string name; int age; } class Boss : Person { int numEmployees; } string serialize(T)(T obj) { // ... iterate over fields and serialize stuff return join([FieldNameTuple!T], ","); } void main() { writeln(serialize(new Person)); // name,age writeln(serialize(new Boss)); // numEmployees writeln(serialize(cast(Person) new Boss)); // name,age } ``` Naturally, when an object is instantiated as a `Boss` but the variable holding it is type `Person`, the version of the template that gets called is `serialize!Person`. It's especially common to run into this if, say, `Person` defined `Person[] friends` and that array was populated by various inherited subclasses that needed to be recognized (we also need to recursively serialize the members of the parent class, but that part's trivial so I'll skip it for now). So, the first basic idea I came up with was using mixins in each serializable class: ```d mixin template Serializable() { static if (hasMember!(BaseClassesTuple!(typeof(this))[0], "serializeMe")) { override string serializeMe() { return serializeTrue(this); } } else { string serializeMe() { return serializeTrue(this); } } } class Person { string name; int age; mixin Serializable; } class Boss : Person { int numEmployees; mixin Serializable; } string serialize(T)(T obj) { return obj.serializeMe(); } private string serializeTrue(T)(T obj) { // ... return join([FieldNameTuple!T], ","); } void main() { writeln(serialize(new Person)); // name,age writeln(serialize(new Boss)); // numEmployees writeln(serialize(cast(Person) new Boss)); // numEmployees } ``` This works, but I kind of don't like using mixins for this for some reason. It feels less obvious that the class itself has been identified as something serializable, and you never know what additional methods or fields the mixin might be declaring. I'd prefer to use UDAs, so I came up with something like: ```d enum Serializable; @Serializable class Person { string name; int age; } @Serializable class Boss : Person { int numEmployees; } string serialize(Object obj) { string runtimeTypeName = typeid(obj).name; static foreach (sym; getSymbolsByUDA!(test_serialize, Serializable)) { if (fullyQualifiedName!sym == runtimeTypeName) return serializeTrue(cast(sym) obj); } assert(false, "Unable to serialize type: "~runtimeTypeName); } private string serializeTrue(T)(T obj) { // ... return join([FieldNameTuple!T], ","); } void main() { writeln(serialize(new Person)); // name,age writeln(serialize(new Boss)); // numEmployees writeln(serialize(cast(Person) new Boss)); // numEmployees } ``` This also works, but it has a problem. We pass the current module directly to `getSymbolsByUDA` (`test_serialize.d`), but if we have classes spread across multiple modules, we need some way to iterate through those as well. Unfortunately I couldn't find any trait related to iterating through all the modules compiled into a project. Could an `allModules` or such thing be added? Or is this non-trivial to the compilation process? So, I ultimately came up with the following. It requires some instantiation at runtime to create lookup tables between real type templates and `typeid` values, and requires a mixin of a mixin since I couldn't find a way to get the module of a symbol as an alias (no `moduleOf!symbol` trait?), but it seems to get the job done (also, I finally went and added the recursive parent class serialization): ```d enum Serializable; @Serializable class Person { string name; int age; } @Serializable class Boss : Person { int numEmployees; } mixin template RegisterSerializer(alias MODULE) { void RegisterSerializer() { static foreach (SYM; getSymbolsByUDA!(MODULE, Serializable)) static if (is(SYM == class)) serialTypes[fullyQualifiedName!SYM] = new SerialType!SYM; } } abstract class SerialTypeBase { string encodeObject(Object obj); } final class SerialType(T) : SerialTypeBase { override string encodeObject(Object obj) { return serializeTrue(cast(T) obj); } } void[0][string] registeredModules; SerialTypeBase[string] serialTypes; string serialize(T)(T obj) { enum string MODULENAME = moduleName!T; if
opCast in class prevents destroy
```d struct A {} class B { A opCast(T : A)() { return A(); } } void main() { auto b = new B(); destroy(b); } ``` fails with ``` dmd2\windows\bin\..\..\src\druntime\import\object.d(4209): Error: template instance `opCast!(void*)` does not match template declaration `opCast(T : A)()` main.d(9): Error: template instance `object.destroy!(true, B)` error instantiating ``` Looks like a similar bug has been reported: https://issues.dlang.org/show_bug.cgi?id=22635 As a workaround, adding an additional opCast: ```d class B { A opCast(T : A)() { return A(); } auto opCast(T)() { return cast(T)super; } } ``` SEEMS to work. Is that safe? Or are consequences not what I'm intending?
Re: Can static variables in methods be local for each object?
On Tuesday, 20 July 2021 at 09:24:07 UTC, Mark Lagodych wrote: Is there a way to make myvar local to each instance of `X` without making it a variable of `X`? Just curious. Sorry if I missed something obvious but is there a specific reason why it isn't just a class member variable? ```d class X { int myvar = 1234; int x(int param) { if (param == 0) return myvar; else { myvar = param; return myvar; } } } ``` ?? Why would you need a static variable inside a method but also have that static variable unique to each class instance, but not stored inside the class? I could see maybe if the class definition were private and you can't change it, in which case you could extend it: ```d class X { // Someone else's module } class MyX : X { int myvar = 1234; int x(int param) { return param ? myvar = param : myvar; } } void main() { auto x1 = new MyX(); auto x2 = new MyX(); x1.x(0).writeln; x2.x(0).writeln; x1.x(17).writeln; x2.x(0).writeln; } ```
Re: What exactly gets returned with extern(C) export string func() ?
On Sunday, 13 June 2021 at 21:13:33 UTC, frame wrote: On Sunday, 13 June 2021 at 10:02:45 UTC, cc wrote: it seems to work as expected with the same C# code. Does D explicitly disallow slices as an extern(C) export parameter type? The spec says that there is no equivalent to type[]. You get a type* instead. I can't seem to get it to work as a return type, but interestingly it does work as an out/pass by ref parameter. D: ```d export void D_testString(out string ret) { ret = "hello".idup; } ``` C#: ```c# public struct DString { public ulong length; public IntPtr ptr; public string str { get { byte[] b = new byte[length]; for (int i = 0; i < (int)length; i++) { b[i] = Marshal.ReadByte(ptr, i); } return Encoding.UTF8.GetString(b); } } } [DllImport("test.dll")] private static extern void D_testString(out DString dd); public static string testString() { DString d; D_testString(out d); return d.str; } ```
What exactly gets returned with extern(C) export string func() ?
D under dmd/Win10/64-bit currently seems to store strings (slices) internally like so: ```d static struct DString { size_t length; immutable(char)* ptr; } static assert(DString.sizeof == string.sizeof); string s = "abcde"; DString d; memcpy(, , s.sizeof); assert(d.length == s.length); assert(d.ptr == s.ptr); ``` If I write a DLL export like: ```d extern(C) export string someDLLFunc() { return "hello"; } ``` and import it in C# (VS .NET): ```c# struct DString { public long length; public IntPtr ptr; } [DllImport("mydll.dll")] extern DString someDLLFunc(); ... DString d = someDLLFunc(); System.Console.WriteLine("dstr: {0} : {1}", d.length, d.ptr); ``` Though C# seems to properly be getting 16 bytes as the return value from `someDLLFunc()`, the length and ptr parameters are both 0. If I explicitly pass a struct back from D instead like so: ```d static struct DString { size_t length; immutable(char)* ptr; this(string str) { length = str.length; ptr = str.ptr; } } extern(C) export DString someDLLFunc() { return DString("hello"); } ``` it seems to work as expected with the same C# code. Does D explicitly disallow slices as an extern(C) export parameter type?
Re: cloning array
On Wednesday, 2 June 2021 at 17:50:13 UTC, Sean wrote: On Wednesday, 2 June 2021 at 15:32:38 UTC, Sean wrote: if so, how can I get the behavior i am searching for? Thank you. My current solution, if anyone wonders : https://github.com/patefacio/d-help/blob/master/d-help/opmix/dup.d You may find the `hasIndirections` template from std.traits useful. ```d import std.traits : hasIndirections, ValueType; import std.range.primitives : ElementType; int[] a; int[][] b; int[string] x; int[][string] y; struct S { int s; } struct T { int[] t; } assert(!hasIndirections!( ElementType!(typeof(a)) )); assert( hasIndirections!( ElementType!(typeof(b)) )); assert(!hasIndirections!( ValueType!(typeof(x)) )); assert( hasIndirections!( ValueType!(typeof(y)) )); assert(!hasIndirections!S); assert( hasIndirections!T); ```
Re: wanting to try a GUI toolkit: needing some advice on which one to choose
On Tuesday, 1 June 2021 at 20:20:34 UTC, Ola Fosheim Grøstad wrote: Web components are becoming a reality, it essentially means that you have code and styling wrapped up as a component, so that you can use it by inserting a custom html-tag in your code. Given the massive amount of web developers... you'll eventually have a crazy amount of components to choose from. Just waiting for Safari: https://caniuse.com/?search=components I think? It's 2021 and I'm still waiting for parent selectors. Even :has() isn't implemented by anything yet.
Re: wanting to try a GUI toolkit: needing some advice on which one to choose
This is overkill for any reasonable application, but I've always wanted to design a whole UI framework in OpenGL, just for the novelty of it. I always end up having to reinvent the wheel for UI elements in my projects anyway. https://streamable.com/2uvt4h
Re: How long does the context of a delegate exist?
On Thursday, 27 May 2021 at 20:46:22 UTC, Adam D. Ruppe wrote: On Thursday, 27 May 2021 at 20:44:21 UTC, frame wrote: Did you mean to add the delegate as GC root or the data? The delegate.ptr property. Is there any way to enforce at compile time that we're not accidentally allocating when creating a delegate, other than being carefully aware of what variables are referenced inside the body? Something like: ```d auto dg = delegate {...} assert(dg.ptr is null, "Oops, we unintentionally allocated on GC here, check delegate body!"); // can't static assert ```
Re: Format
On Saturday, 22 May 2021 at 03:14:35 UTC, cc wrote: Oops, disregard this. I had an error in my imports. It does in fact work in @safe. I should add as an aside then that there is an issue of errors from the body of a toString template not being displayed, and instead the template being silently skipped, e.g.: ```d @safe void toString(W)(ref W writer) if (isOutputRange!(W, char)) { writer.formattedWrite("FOO:%s", x); syntactically correct; // Program will compile without error, but this function will now never be called } ``` I ran into a similar challenge with opDispatch some time ago: https://forum.dlang.org/post/axgwhzzawncbpcvqq...@forum.dlang.org In this case I assume it's some consequence of NOT wanting to emit a warning or error for every single class or struct that doesn't have a templated toString when the various output writers go looking for one. Something like this can help reveal errors, not sure if there's an easier way: ```d unittest { struct DebugWriter { void put(C)(C c) {} } DebugWriter wr; Foo foo; foo.toString(wr); } ``` `Error: undefined identifier 'syntactically'` `Error: template instance 'amemfailuretest.Foo.toString!(DebugWriter)' error instantiating`
Re: Format
On Saturday, 22 May 2021 at 03:07:10 UTC, cc wrote: Ahh, in that case it would appear formattedWrite isn't @safe at all. Looks like you have to stick with put()? ```d @safe void toString(W)(ref W writer) if (isOutputRange!(W, char)) { //writer.formattedWrite!("FOO:%s", x); // fails import std.conv; put(writer, "FOO:"); put(writer, x.to!string); } ``` Oops, disregard this. I had an error in my imports. It does in fact work in @safe.
Re: Format
On Friday, 21 May 2021 at 16:53:48 UTC, drug wrote: 21.05.2021 18:28, cc пишет: On Friday, 21 May 2021 at 14:19:03 UTC, newbie wrote: Thank you, and formatValue? formattedWrite should handle this. ```d @safe struct Foo { int x = 3; void toString(W)(ref W writer) if (isOutputRange!(W, char)) { writer.formattedWrite("Foo(%s)", x); } } Foo foo; writeln(foo); ``` Oddly enough this form of toString works from @safe code even if it's not marked @safe, or even marked @system... I guess that because it is a template so the compiler is able to deduce its attributes. What about the case when it is marked @system - in this case compiler ignore that method due to the fact that it is @system and generate the default one. Because your implementation of the method is equal to the default implementation you didn't see the difference but it exists. Try to make your implementation of `toString` different and you'll see. Ahh, in that case it would appear formattedWrite isn't @safe at all. Looks like you have to stick with put()? ```d @safe void toString(W)(ref W writer) if (isOutputRange!(W, char)) { //writer.formattedWrite!("FOO:%s", x); // fails import std.conv; put(writer, "FOO:"); put(writer, x.to!string); } ```
Re: Format
On Friday, 21 May 2021 at 14:19:03 UTC, newbie wrote: Thank you, and formatValue? formattedWrite should handle this. ```d @safe struct Foo { int x = 3; void toString(W)(ref W writer) if (isOutputRange!(W, char)) { writer.formattedWrite("Foo(%s)", x); } } Foo foo; writeln(foo); ``` Oddly enough this form of toString works from @safe code even if it's not marked @safe, or even marked @system...
Re: struct destructor
On Saturday, 15 May 2021 at 18:24:19 UTC, Alain De Vos wrote: Thanks, good idea but, It does not initiate a GC cycle or free any GC memory. Personally I wish D would re-implement "delete" and make it "just work" like one would assume, but from what I've seen there have been many many debates on that and it isn't going to happen. If the goal is to absolutely squeeze the GC back down after using new or dynamic arrays, I find destroy + GC.free often fails to do the trick (e.g. GC.stats.usedSize remains high). For whatever reason (I glanced at the code but haven't found the magic yet), the deprecated __delete does a more thorough job of making sure that memory actually gets "given up" on a collection cycle (particularly if you invoke it manually with `GC.collect(); GC.minimize();`. Presumably this isn't a desirable coding behavior, though. In my field (games), I do do something like this after initially loading the data to free up all the unused clutter and scaffolding, but it's very slow to call it every frame if you've been using the GC to create and delete game entities. So like Adam says, standard C malloc/free are probably the best way to go in this case. ```d import core.stdc.stdlib; import core.lifetime; class Foo {} auto foo = cast(Foo) malloc(__traits(classInstanceSize, Foo)); emplace!Foo(foo, /*constructor args*/); // ... destroy(foo); free(cast(void*)foo); ``` Another alternative is something like the memutils library: https://code.dlang.org/packages/memutils ```d class Foo {} auto foo = ThreadMem.alloc!Foo(/*constructor args*/) ThreadMem.free(foo); // calls destroy for you, but can still destroy manually ``` You'll still need to be very careful about any GC mem that gets allocated within a class like this as it can get lost into the ether and cause permanent bloat. I've been doing a lot of iteration tests lately across a whole bunch of different memory management solutions and the state of discrete memory management in D for gaming applications is.. not great. I love D, but for all that it's designed to help reduce programmer error, it goes the opposite way once you start breaking free of the GC and having to be extra careful tiptoeing around its edges. Unfortunately I don't like doing the pure @nogc/betterC route either, the GC is still really handy to have when you need it (and are aware that it's being used!), but GC collections during high intensity gaming are unacceptable (and deferring them to some later point doesn't help much either). Fair warning, I'm not one of the D elite with a deep guru-level knowledge of just precisely how everything is operating under the hood, so part of this may come down to learning better practices, but a problem I see IMO is a perceived lack of support or sympathy for coders who want to use the GC when it's nice, but not have it smack them in the face when it isn't. Even with the various articles and forum threads explaining D's memory options, there's still a general air of "You really should just be using the GC, so enjoy your no-man's land, you're on your own." Whether this is only an unfair perception and matter of documentation, or something that actually needs to be addressed in the language, is beyond simply me to decide, but I think a lot of outsiders coming into D may run into the same situation.
What is the difference between these template declaration forms?
Are these identical? Or is there a different usage for the (T : something) form? ```d auto opCast(T)() if (is(T == bool)) { return _obj !is null; } ``` ```d auto opCast(T : bool)() { return _obj !is null; } ```
Re: Learning D
On Friday, 14 May 2021 at 15:30:06 UTC, Imperatorn wrote: https://www.amazon.com/Programming-Language-Former-Python-Developers-ebook/dp/B08MD7ZB2X Anyone read it? Haven't read it, the title has me at the first five words though.
Re: String "dequote" in phobos?
On Thursday, 13 May 2021 at 16:40:29 UTC, Imperatorn wrote: Wouldn't this just this do that? 樂 ```d string dequote(string s) { return s[1..$-1]; } ``` The idea would be for situations where it isn't known in advance whether the string is quoted, if it is quoted properly, and whether there are escaped quotes within the string that need to be un-escaped. Additionally some data sources may handle escaping quotes in strings differently (e.g. `\"` vs `""`)
String "dequote" in phobos?
Does something to dequote (unquote? or what would you call it?) a string exist in the standard library? I didn't see one in std.string, just wondering before reinventing the wheel. Something like: ```d assert(dequote(`"foo"`) == "foo"); assert(dequote(`'foo'`) == "foo"); assert(dequote(`"foo's"`) == "foo's"); assert(dequote(`'foo "bar"'`) == `foo "bar"`); assert(dequote(`"fo\"o"`) == `fo"o`); dequote(`"fo"o"`); // bad quoting, maybe throw an exception here or something? ```
Re: Question about property & method access scope.
On Tuesday, 11 May 2021 at 09:10:02 UTC, Vinod K Chandran wrote: Hi all, I am practising D with a win api GUI hobby project. I have a Window class and it resides in module window.d My WndProc function resides in another module named wnd_proc_module.d Inside my WndProc, I get the Window class like this. ```d Window win = cast(Window) (cast(void*) GetWindowLongPtrW(hWnd, GWLP_USERDATA)) ; ``` So in many situations, I need to check some boolean properties of Window class and call some functions of Window class in WndProc. But I don't want to expose those props and functions to the user. So if I make them private, I can't access them inside the WndProc function. How do solve this issue. Thanks in advance. The `package` protection attribute should work here if the modules reside in the same package (directory)? ```d module mywindow.window; import mywindow.wnd_proc_module.d class Window { package int x, y; } ``` ```d module mywindow.wnd_proc_module.d import mywindow.window; class Proc { Window win; void doStuff() { win.x = 3; } } ```
Re: OutOfMemoryError in D DLL appending to module-level array
On Sunday, 2 May 2021 at 02:42:46 UTC, Adam D. Ruppe wrote: On Sunday, 2 May 2021 at 02:34:41 UTC, cc wrote: which seems to fix it, but I'm not entirely sure what's going on, if this is expected behavior, if that's the correct way to handle it, and so on. Oh I've been working on this the last couple weeks and having a hard time reproducing outside the work application. In the work app, the GC wasn't scanning the dll's TLS variables and freeing them prematurely. In a sample test program, I used a thing kinda like yours, if a dll creates a thread and calls back into the exe you get a separate problem of partially initialize data. D dlls on Windows work in simple cases right now but break down in more advanced cases. The good news is there's major fixes coming soon - my druntime hack might be coming, gdc is getting full dll support very soon from mingw, there's a good chance ldc is going to in a release or two as well outside mingw. But the bad news is none of that is actually out right now, so dll + tls variables (which includes the top-level things on modules) are potentially buggy among other things like duplicated symbols. You might find some improvement making your variable __gshared there. But if you can do any reduced test case I'd really appreciate it. More tests that we can do in public is better! Cool, thanks for the update. Setting it as __gshared does seem to work. I put together some test cases here: https://gitlab.com/-/snippets/2114152 It's got the DLL written in D, and test programs for loading it in D, C#, and C++. I haven't done much .NET interop stuff but it seems to work. I'd welcome any recommendations on how to improve the interfaces if there are any, I made a little mixin to create C wrappers for the member functions since that seems to be the suggested solution for calling class methods.
Re: OutOfMemoryError in D DLL appending to module-level array
On Sunday, 2 May 2021 at 02:34:41 UTC, cc wrote: [...] Just to add, only appending to the array seems to give OutOfMemoryErrors. I can idup strings, call stdc malloc, etc just fine.
OutOfMemoryError in D DLL appending to module-level array
Ordinarily, it seems legal to append to an array that has been declared at module level (or as a static class member) that hasn't been otherwise initialized, for example: ```d class Foo {} private Foo[] cache; void main() { auto foo = new Foo(); cache ~= foo; } ``` However, when building code like this as a DLL, such as: ```d class Foo {} private Foo[] cache; extern(C) export Foo createFoo() { auto foo = new Foo(); cache ~= foo; return foo; } ``` and then calling it from another application (in this case, C#), I get `core.exception.OutOfMemoryError@src\core\exception.d(647): Memory allocation failed` at the `cache ~= foo;` line. I was able to get around this by adding: ```d static this() { cache.length = 0; } ``` which seems to fix it, but I'm not entirely sure what's going on, if this is expected behavior, if that's the correct way to handle it, and so on. Does it have something to do with the D runtime being initialized differently in a DLL versus a statically linked program? I am calling Runtime.initialize() as expected when the DLL is attached.
Re: win64 DLL stdout printing after main process completes
On Monday, 26 April 2021 at 13:44:19 UTC, frame wrote: On Sunday, 25 April 2021 at 15:01:25 UTC, cc wrote: Adding a note in case anyone stumbles across this with a similar problem: Adding `stdout.setvbuf(0, _IONBF);` to both the main and DLL will cause D to autoflush after every write call without requiring a manual flush (which seems to happen quite often when running under anything other than a basic Windows command prompt). I cannot reproduce this on Windows 10. It would be just interesting to know your compiler version and OS and if you have installed any Visual Studio tools or Visual C runtimes, thanks. Win10 64-bit DMD32 D Compiler v2.096.0-dirty Sublime Text 3.1.1 Build 3176 Visual Studio 2019 is installed, as well as... quite a few runtimes, multiple for Visual C++ 2005, 2008, 2010, 2012, 2013, 2015-2019. The buffering also happens under cygwin shells (I'm not building with cygwin, I just like using their bash shell). If I run a D program through the basic cmd.exe, it runs with no stdout buffering. However any other situation (shell, sublime build+output capture, etc) buffering somehow gets enabled, unless I explicitly disable it in code or wrap the write* functions with stdout.flush() wrappers. This has happened for me for many versions of the dmd compiler stretching back years, building both 32-bit and 64-bit executables.
Re: win64 DLL stdout printing after main process completes
On Monday, 19 April 2021 at 18:32:15 UTC, Adam D. Ruppe wrote: On Monday, 19 April 2021 at 18:05:46 UTC, cc wrote: This seems to work if I flush after every printf or write in both main and the dll. I was under the impression they were supposed to share the same IO buffers though, is this not the case? Very little in D dlls right now are shared, so there's duplicate buffers and functions in the dll do not necessarily affect the exe's copies. It basically works in most cases but this can cause some quirks and bugs in some situations. That makes sense, thanks. Adding a note in case anyone stumbles across this with a similar problem: Adding `stdout.setvbuf(0, _IONBF);` to both the main and DLL will cause D to autoflush after every write call without requiring a manual flush (which seems to happen quite often when running under anything other than a basic Windows command prompt).
Re: win64 DLL stdout printing after main process completes
On Monday, 19 April 2021 at 16:04:28 UTC, Mike Parker wrote: On Monday, 19 April 2021 at 14:55:03 UTC, cc wrote: And upon running, the output I receive is: ``` [Main] Start [Main] x: 5 [Main] Finished [Main] END [dll] DLL_PROCESS_ATTACH [dll] static this for mydll [dll] MyDLL_Test [dll] DLL_PROCESS_DETACH [dll] static ~this for mydll ``` I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared? It's probably just due to buffering. Insert a fflush(stdout) after the calls to printf in your DLL and see what happens. This seems to work if I flush after every printf or write in both main and the dll. I was under the impression they were supposed to share the same IO buffers though, is this not the case?
Re: win64 DLL stdout printing after main process completes
On Monday, 19 April 2021 at 16:00:25 UTC, frame wrote: You miss a core.stdc.stdio import in main(). I also omit the def-File, maybe you have an error in it? It shouldn't be necessary to include. It just did: ``` dmd -m64 -ofmydll.dll -L/DLL mydll.d ``` Sorry, here's the def file, taken from the wiki example. ``` LIBRARY "mydll.dll" EXETYPE NT SUBSYSTEM WINDOWS CODE SHARED EXECUTE DATA WRITE ``` Incidentally I get some warnings regarding it when I compile: ``` mydll.def(2) : warning LNK4017: EXETYPE statement not supported for the target platform; ignored mydll.def(3) : warning LNK4017: SUBSYSTEM statement not supported for the target platform; ignored mydll.def(4) : warning LNK4017: CODE statement not supported for the target platform; ignored mydll.def(5) : warning LNK4017: DATA statement not supported for the target platform; ignored ``` Are all those lines were intended for win32 dlls and whatever the x64 equivalents are are different? Also, the example at the D wiki URL had a -L/IMPLIB in the command line but I get `LINK : fatal error LNK1146: no argument specified with option '/IMPLIB'` with that so I removed it.
win64 DLL stdout printing after main process completes
I'm not sure if this is something unique to D or not, but I've having a minor issue where stdout output from a DLL (either via printf or phobos std.stdio write) is not displayed until after the main process has completed. I'm making a project based around the example at https://wiki.dlang.org/Win32_DLLs_in_D which I've heard is a little out of date but I've gotten it working nonetheless. I have the following project files: ```d // mydll.d module mydll; import core.runtime; import core.stdc.stdio; import core.stdc.stdlib; import core.sys.windows.windows; extern(Windows) BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved) { switch (ulReason) { case DLL_PROCESS_ATTACH: printf("[dll] DLL_PROCESS_ATTACH\n"); Runtime.initialize(); break; case DLL_PROCESS_DETACH: printf("[dll] DLL_PROCESS_DETACH\n"); Runtime.terminate(); break; case DLL_THREAD_ATTACH: printf("[dll] DLL_THREAD_ATTACH\n"); return false; case DLL_THREAD_DETACH: printf("[dll] DLL_THREAD_DETACH\n"); return false; default: } return true; } export int MyDLL_Test() { printf("[dll] MyDLL_Test\n"); return 5; } static this() { printf("[dll] static this for mydll\n"); } static ~this() { printf("[dll] static ~this for mydll\n"); } ``` ```d // mydll.di module mydll; export int MyDLL_Test(); ``` ```d // main.d import mydll; pragma(lib, "mydll.lib"); import core.sys.windows.windows; void main() { printf("[Main] Start\n"); scope(exit) printf("[Main] END\n"); int x = MyDLL_Test(); printf("[Main] x: %d\n", x); printf("[Main] Finished\n"); } ``` DLL compilation command line: `dmd -m64 -ofmydll.dll -L/DLL mydll.d mydll.def` Main command line: `rdmd -m64 main.d` And upon running, the output I receive is: ``` [Main] Start [Main] x: 5 [Main] Finished [Main] END [dll] DLL_PROCESS_ATTACH [dll] static this for mydll [dll] MyDLL_Test [dll] DLL_PROCESS_DETACH [dll] static ~this for mydll ``` I would expect the first three lines of dll output to precede the "[Main] x:" line at least. Is there something I'm doing wrong? Do I need to somehow pass a reference to the main stdio to the DLL's D runtime similar to how the GC can be shared?
Package import order with extern(C++) classes and std.container.array failure
Just encountered this compilation failure in DMD winx64 2.096, which previously worked in 2.095 and prior versions. Just wondering if it's a bug, or a new issue to keep in mind when importing modules? Sorry for the complex nature of this scenario but I'll try to keep it as simple as possible. Given the following 4-file setup: // main.d import cream; void main() {} // cream/package.d module cream; public import cream.dcream; public import cream.callbacks; // cream/callbacks.d module cream.callbacks; import cream; extern(C++) class CallbackBase {} // cream/dcream.d module cream.dcream; import cream; import std.container.array; Array!CallbackBase callbackTracker; Compilation fails with the following error: C:\D\dmd2\windows\bin\..\..\src\phobos\std\container\array.d(519): Error: incompatible types for array comparison: `const(CallbackBase[])` and `const(CallbackBase[])` C:\D\dmd2\windows\bin\..\..\src\phobos\std\container\array.d(189): Error: template instance `std.container.array.RangeT!(const(Array!(CallbackBase)))` error instantiating C:\D\dmd2\windows\bin\..\..\src\phobos\std\container\array.d(528): instantiated from here: `RangeT!(Array!(CallbackBase))` cream\dcream.d(4):instantiated from here: `Array!(CallbackBase)` It seems I can fix this by changing the order the other modules are imported in package.d like so: // cream/package.d module cream; public import cream.callbacks; public import cream.dcream; I'm curious why this worked in prior dmd versions, and if it's something I'll need to worry about going forward when creating complex multi-file modules.
Re: Problem with templated alias as delegate parameter type
On Tuesday, 12 January 2021 at 21:32:14 UTC, Ali Çehreli wrote: On 1/12/21 12:58 PM, cc wrote: > void send(T query, void delegate(T.RESPONSE) callback) { That wants a delegate that takes a T.RESPONSE (PingResponse in this case). However, the following lambda is in fact a template: > send(PingQuery("helo"), (resp) { You specify the type there and it works: send(PingQuery("helo"), (PingResponse resp) { Ali That seems to work, thanks. I ended up having to define a second template parameter: template send(T,TR) if (is(TR == T.RESPONSE)) { void send(T query, void delegate(TR) callback) { ...
Problem with templated alias as delegate parameter type
Given the following program: struct PingQuery { string msg; } struct PingResponse { string msg; } template send(T) { void send(T query, void delegate(PingResponse) callback) { writefln("Sending: %s", query); if (callback) { PingResponse resp; resp.msg = query.msg; callback(resp); } } } void main() { send(PingQuery("helo"), (resp) { writefln("Got response: %s", resp); }); } This works, but as you can see the PingResponse struct is hardcoded in the send function. If I try to make it a part of the template in a way such as this: struct PingQuery { alias RESPONSE = PingResponse; string msg; } struct PingResponse { string msg; } template send(T) { static assert(is(T.RESPONSE == PingQuery.RESPONSE)); // this succeeds at least void send(T query, void delegate(T.RESPONSE) callback) { writefln("Sending: %s", query); if (callback) { T.RESPONSE resp; resp.msg = query.msg; callback(resp); } } } void main() { send(PingQuery("helo"), (resp) { writefln("Got response: %s", resp); }); } I get: delegatetest.d(48): Error: template `delegatetest.send` cannot deduce function from argument types `!()(PingQuery, void)`, candidates are: delegatetest.d(35):`send(T)(T query, void delegate(T.RESPONSE) callback)` Same error if I use a nested struct (e.g. struct PingQuery { struct RESPONSE {} }) instead of an alias. Currently using DMD32 D Compiler v2.095.0-dirty (win64).
Re: Renamed but non-selective import?
On Tuesday, 12 January 2021 at 20:19:20 UTC, ag0aep6g wrote: On 12.01.21 21:09, cc wrote: import core.sys.windows.windows; import mymodule; // contains a struct named MSG Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG` vs import core.sys.windows.windows : winMSG = MSG; // this leaves out other symbols Error: undefined identifier `HWND` Error: undefined identifier `LPCSTR` import core.sys.windows.windows; import mymodule; alias MSG = mymodule.MSG; alias winMSG = core.sys.windows.windows.MSG; Ahh simple enough, thanks.
Renamed but non-selective import?
Is it possible to import all symbols of a module, while renaming just one of them? It seems like doing an import with renaming automatically makes it selective. In the example below, I'd prefer not to have to use the fully qualified name for mymodule.MSG every time e.g.: import core.sys.windows.windows; import mymodule; // contains a struct named MSG Error: `core.sys.windows.winuser.MSG` ... conflicts with `mymodule.MSG` vs import core.sys.windows.windows : winMSG = MSG; // this leaves out other symbols Error: undefined identifier `HWND` Error: undefined identifier `LPCSTR`
Re: constructing labels for static foreach inside switch inside foreach
On Wednesday, 8 July 2020 at 02:06:01 UTC, Steven Schveighoffer wrote: OK, so I have a situation where I'm foreaching over a compile-time list of types. Inside the loop, I'm using a second loop over a set of input. Inside that loop, I'm using a switch on the input, and inside the switch, I'm foreaching over the type's members, to construct a switch that can handle member names (this is for serialization). If I encounter a certain name, then I want to break out of the inner loop (it's a while loop) So naturally, I have to use break statements with labels like: innerloop: while(haveMoreData) switchstmt: switch(nextDataElement) { static foreach(name; __traits(allMembers, T)) { case name: ... // handle it break switchstmt; } case "STOP": break innerloop; } Seems simple enough, except that this inner portion is unrolled, and if I have more than one type to run this on, I already have an "innerloop" label defined. Is there a way to define a label using a mixin or something? or do I have to wrap this in a function? Is there another way to approach this? -Steve I think I ran into similar problems due to the requirement to use a labeled break inside static foreach. I got around it by defining enums when my target was found and checking if it existed via __traits(compiles) to "ignore" the rest of the loop. Sorry if I got what you're trying to accomplish wrong or this is too ugly: class Foo { @(RPC) bar(int x, float f, string s) { // ... } } class Remoter(T) { void opDispatch(string s, SA...)(SA sargs) { alias A = getSymbolsByUDA!(T, RPC); static foreach (idx, FUNC; A) { static if (!__traits(compiles, FOUND) && hasUDA!(FUNC, RPC) && FUNCNAME!FUNC == s && SA.length == (Parameters!FUNC).length) { version(CheckImplicitlyConvertibleArgs) { static foreach (argi; 0 .. SA.length) { static if (!__traits(compiles, mixin(format("MISMATCH_%d", idx { static if (isImplicitlyConvertible!(SA[argi], (Parameters!FUNC)[argi])) { //pragma(msg, format("implc ok: %s => %s", SA[argi].stringof, (Parameters!FUNC)[argi].stringof)); // Parameter Ok } else { pragma(msg, format("RPC argument[%s] of %s is not implicitly convertible: %s => %s", argi, FUNCNAME!FUNC, SA[argi].stringof, (Parameters!FUNC)[argi].stringof)); mixin(`enum bool `~format("MISMATCH_%d", idx)~` = true;`); } } } static if (!__traits(compiles, mixin(format("MISMATCH_%d", idx { enum FOUND = idx; //pragma(msg, format("and we found: %s", FOUND)); } } else { enum FOUND = idx; } } } static if (__traits(compiles, FOUND)) { alias FUNC = A[FOUND]; // generate a packet to transmit that corresponds to RPC function call } else { static assert(0, format("No matching function found for %s%s", s, SA.stringof)); } } } Remoter!foo remote; remote.bar(4, 3.14f, "hello"); // succeeds remote.bar("hi", 12); // static assert fail
Should getSymbolsByUDA work with member variables?
This compiles: class Foo { int x; @(1) void y() {} this() { static foreach (idx, field; getSymbolsByUDA!(Foo, 1)) { } } } This does not: class Foo { @(1) int x; void y() {} this() { static foreach (idx, field; getSymbolsByUDA!(Foo, 1)) { } } } Error: value of `this` is not known at compile time Is there an equivalent for getSymbolsByUDA for member variables, or is this a bug?
Re: Get compilation errors within opDispatch?
On Monday, 17 February 2020 at 17:01:12 UTC, Adam D. Ruppe wrote: It sometimes helps to write it out log-form foo.opDispatch!"hello"(5); should give the full error. this btw is one of the most annoying missing errors in d... This worked, thank you! On Monday, 17 February 2020 at 16:45:53 UTC, Ali Çehreli wrote: Try dmd command line switch -verrors=spec. Ali This technically also worked, but the error was buried on line 5431 of the 9857-line result.
Get compilation errors within opDispatch?
Is there any way to see the compilation errors that occurred within an opDispatch template? struct Foo { void opDispatch(string s, SA...)(SA sargs) { literally anything; } } Foo foo; foo.hello(5); Result: Error: no property `hello` for type `Foo` Desired result: Error: undefined identifier `literally`
Re: How to use labeled break in static foreach?
Here's a more involved example of what I'm trying to accomplish. Is there an easier/cleaner way to do this? (This is still a bit reduced, what I'm actually trying to do is compare whether a given variadic typetuple passed to opDispatch is implicitly convertible to one of the parameter definitions of overloaded functions with the same name on another object). import std.meta; struct Test { int[3] x; } enum A = Test([1, 3, 3]); enum B = Test([5, 6, 7]); enum C = Test([5, 6, 7]); enum D = Test([8, 9, 0]); enum ARRS = AliasSeq!(A, B, C, D); enum TESTER = Test([5, 6, 7]); static foreach (ai, af; ARRS) { static if (!__traits(compiles, FOUND)) { static foreach (idx, field; af.x) { // Have to declare a different MISMATCH enum for each inner loop iteration // unless we enclose it in its own {} scope, but if we do that then FOUND // is not visible to the outer loop static if (!__traits(compiles, mixin(format("MISMATCH_%d", ai { static if (TESTER.x[idx] != af.x[idx]) { mixin(`enum bool `~format("MISMATCH_%d", ai)~` = true;`); } } static if (idx == af.x.length - 1 && !__traits(compiles, mixin(format("MISMATCH_%d", ai { enum FOUND = ai; } } } } static if (__traits(compiles, FOUND)) { pragma(msg, format("entry #%d matches: %s", FOUND, ARRS[FOUND])); } else { static assert(0, "Got no match..."); }
How to use labeled break in static foreach?
import std.meta; enum A = AliasSeq!(1, 2, 3, 4); THREELOOP: static foreach (idx, field; A) { static if (field == 3) { pragma(msg, "Got a 3!"); break THREELOOP; } static if (idx == A.length - 1) { static assert(0, "Got no 3..."); } } What I'd like to achieve in this example is for compilation to fail if the given tuple doesn't contain a matching item. Is there an easy way to do this? Trying to break out of the static foreach gives me Error:enclosing label `THREELOOP` for `break` not found In this reduced example, I was able to accomplish this by setting some enum within the successful comparison body and then checking e.g. static if (!__traits(compiles, FOUND)) but this breaks down once I start dealing with multiple levels of scope.
Re: Global version/debug statements in file?
On Wednesday, 12 February 2020 at 09:28:15 UTC, Simen Kjærås wrote: 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 Ahh missed that, that should do it, thanks!
Re: Is there a std.zip.ZipArchive isDir or isFile method?
It looks like 004 (octal) is the flag for directories on linux, but it does seem that std.zip is explicitly returning 0 if the file was created on the opposite platform re: Posix vs Windows, which is... odd. @property @nogc nothrow uint fileAttributes() const { version (Posix) { if ((_madeVersion & 0xFF00) == 0x0300) return _externalAttributes >> 16; return 0; } else version (Windows) { if ((_madeVersion & 0xFF00) == 0x) return _externalAttributes; return 0; } else { static assert(0, "Unimplemented platform"); } } Looks like the only way around it is modifying std.zip? Adding something like: @property bool isDir() const { enum uint FILE_ATTRIBUTE_DIRECTORY = 0x10; // WINNT.h enum uint S_IFDIR = 0x4000; // sys/stat.h version(Windows) { if ((_madeVersion & 0xFF00) == 0x0300) // Archive made on Posix return cast(bool) (_externalAttributes & (S_IFDIR << 16)); return cast(bool) (_externalAttributes & FILE_ATTRIBUTE_DIRECTORY); } else version(Posix) { if ((_madeVersion & 0xFF00) == 0x0300) // Archive made on Posix return cast(bool) (_externalAttributes & (S_IFDIR << 16)); return cast(bool) ((_externalAttributes) & FILE_ATTRIBUTE_DIRECTORY); } else { static assert(0, "Unimplemented platform"); } } will let me do this: void main() { foreach (zipfile; ["windowstest.zip", "linuxtest.zip"]) { writeln(zipfile); auto zip = new ZipArchive(std.file.read(zipfile)); foreach (fn, am; zip.directory) { writefln("%24s %5s %s", fn, am.isDir, am.fileAttributes); } } } Results on Windows: windowstest.zip a.txt false 32 testdir/ true 16 testdir/b.txt false 32 linuxtest.zip a.txt false 0 testdir/ true 0 testdir/b.txt false 0 Results on Linux: windowstest.zip testdir/ true 0 testdir/b.txt false 0 a.txt false 0 linuxtest.zip testdir/ true 16893 testdir/b.txt false 33204 a.txt false 33204
Global version/debug statements in file?
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. I tried using a mixin, such as: // constants.d module constants; enum VERSIONS = q{ version=Compress; }; // main.d import constants; mixin(VERSIONS); void main() { version(Compress) writeln("Compress it!"); version(Decompress) writeln("Decompress it!"); } This does seem to work inside function bodies, but not at module scope in the importing file. e.g.: // main.d import constants; mixin(VERSIONS) version(Compress) { ... } Gives: Error: version `Compress` defined after use
Re: Is there a std.zip.ZipArchive isDir or isFile method?
On Monday, 3 February 2020 at 13:26:38 UTC, mark wrote: I'm using std.zip.ZipArchive to read zip files, e.g.: auto zip = new ZipArchive(read(filename)); // ... foreach (name, member; zip.directory) { if (name.endsWith('/')) // skip dirs continue; mkdirRecurse(dirName(name)); zip.expand(member); write(name, member.expandedData()); } As you can see, I am detecting directories with a crude test. I really wish there was a method for this: and if there is, could you give me the link 'cos I can't see one in the docs? (BTW The code above is slightly simplified: the real code won't unzip if there's an absolute path or .. present and also ensures that all members are unzipped into a subdir even if the zip has top-level names.) I couldn't find one either, I had to do this: version(Windows) { enum uint FILE_ATTRIBUTE_DIRECTORY = 0x10; } auto zip = new ZipArchive(buffer); foreach (fn, am; zip.directory) { if (am.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) ... is directory else ... is file } As I'm looking at my code for this I'm also reminded that different zip files can internally store path separators as either \ or / depending on the platform that created them so you may need to be careful about that too. I have a bit for this that simply does: version(StandardizePathSeparators) { string filename = fn.replace("\\", "/"); } else { string filename = fn; }