Re: CTFE write message to console
On Friday, 5 April 2024 at 07:37:20 UTC, Paolo Invernizzi wrote: pragma(msg, x) ? No. `__ctfeWrite(x)` is executed inside an executing function like any other statement in it, and can have an argument `x` computed during that execution. It is defined to output the computed text `x` to stderr when the function it is a part of is called as CTFE by the compiler and to be a no-op if that function is called at run time in the compiled executable. So it is a replacement for `std.stdio.write` in a CTFE function, handy among other things for reporting what's going on during the execution of that function by the compiler. `pragma(msg, x)` works during its *compilation*, so putting it as a line in a CTFE-called function would not execute it when the function is called by the compiler. That being the case, `x` may not be a value computed when that function executes. Such a value is "not available at compile time", only at CTFE run time. The CTFE function is not running when it is being compiled. It is possible that `x` in `pragma(msg, x)` be computed with a call to a function as its return value, i.e. computed by CTFE, but that call will be made when `pragma(msg, x)` is compiled, and is a part of compiling it. Only when the function has returned producing `x` does the `pragma(msg, x)` do its work.
Re: CTFE write message to console
On Thursday, 4 April 2024 at 15:47:53 UTC, Richard (Rikki) Andrew Cattermole wrote: Oh hey! https://github.com/dlang/dmd/pull/16250 It was implemented literally 2 weeks ago! Nightly should have it https://github.com/dlang/dmd/releases/tag/nightly Wow! Happy that's in. It was a bit mysterious, but now that request says it was never implemented. Until now. Just what I want!
Re: CTFE write message to console
On Thursday, 4 April 2024 at 15:07:21 UTC, Richard (Rikki) Andrew Cattermole wrote: Ah yes, I forgot about that particular thing, doesn't see much use as far as I'm aware. It should be working though. ```D enum X = computeX("A message"); string computeX(string msg) { auto s = "CTFE msg: "; auto x = imported!"std.format".format("%s%s\n", s, msg); __ctfeWrite(x); return x; } void main() { import std.stdio; writeln(X); } ``` Produces no output on compilation, and writes out `CTFE msg: A message` when run.
Re: CTFE write message to console
On Thursday, 4 April 2024 at 14:06:19 UTC, Richard (Rikki) Andrew Cattermole wrote: ```d static assert(0, "message"); ``` Or if it is known to be CTFE'd ```d assert(0, "message"); ``` Just a warning, its a one time use only for both. No other way to do it. That's ... unfortunate. Some search of the forum led me to some [decade plus old discussion](https://forum.dlang.org/post/j1n1m2$24p0$1...@digitalmars.com) of a possible CTFE writeln function that would be a no-op at runtime, which to my surprise led me to find [core_builtins.__ctfeWrite](https://dlang.org/phobos/core_builtins.html#.__ctfeWrite) but when I tried it out, it compiled yet output no text to the console. Given your remarks I suppose I should have expected this.
Re: std.traits.ParameterIdentifierTuple problem
On Monday, 1 April 2024 at 18:28:16 UTC, Nick Treleaven wrote: On Sunday, 31 March 2024 at 23:05:44 UTC, Carl Sturtivant wrote: Yes, it's not possible to instantiate a function type. But with extern it seems the semantics is fine as a function is not being instantiated. It is merely associating a name with a type: in what sense is this instantiation in any reasonable way? Yes there is no instantiation for extern. But what would be the use of allowing an extern function type instance, when there's no way to instantiate it? 1. For compile time work that uses the name but not the function it nominally refers to. That's what I wanted it for: `ParameterIdentifierTuple` might actually work on that. 2. In fact the definition might refer to a function defined in another module, for example brought in by ImportC. It's an alternative way of writing the signature of an external function. Why rule it out when it is reasonable? The first could also work with an explicitly uninstantiated function, as in `enum FUNCTYPE f = void;` hence my second attempt above. As long as there are compile-time actions that work on functions but not their types, this would be a way to work around that.
Re: std.traits.ParameterIdentifierTuple problem
On Sunday, 31 March 2024 at 11:35:39 UTC, Nick Treleaven wrote: If a function type does include identifiers, then would two function types with the same argument types but different identifiers compare equal using `is`? Yes. That is the idea. Define `is` to work this way. Yes, it's not possible to instantiate a function type. But with extern it seems the semantics is fine as a function is not being instantiated. It is merely associating a name with a type: in what sense is this instantiation in any reasonable way?
Re: std.traits.ParameterIdentifierTuple problem
On Saturday, 30 March 2024 at 22:37:53 UTC, Carl Sturtivant wrote: Incidentally, I tried ```D extern typeof(foo) func; ``` to say that func was an actual function (`extern` so defined elsewhere) whose type was the type of the function `int foo(int num, string name, int);` so I can then use `ParameterIdentifierTuple` on a function, not a type, but the compiler said `bug1.d(5): Error: variable ``bug1.func`` cannot be declared to be a function`. Seems unreasonable given the implied semantics. The word *variable* in that error message caught my eye and it struck me that in some sense a function is a constant, not a variable, we have function pointers for the last. So I tried ```D enum typeof(foo) func = void; ``` to see if I could escape this difficulty. Sadly got exactly the same error message, even though no variable was involved.
Re: std.traits.ParameterIdentifierTuple problem
On Saturday, 30 March 2024 at 21:07:35 UTC, Nick Treleaven wrote: Although `.stringof` on a function type does include the parameter names, the names are not really part of the type - see: https://github.com/dlang/phobos/pull/3620#issuecomment-288469685 Perhaps `ParameterIdentifierTuple` should give a compile error when given a function type. I'm inclined to a view that keeps more "it just works" options open. Regard the parameter names as a part of the type (which I am very grateful for them being currently) and just regard part of the definition of "type equality" as being to ignore parameter names when comparing types. With this viewpoint, ParameterIdentifierTuple should be repaired to work with function types just as it works with functions, and the current behavior is a bug. Incidentally, I tried ```D extern typeof(foo) func; ``` to say that func was an actual function (`extern` so defined elsewhere) whose type was the type of the function `int foo(int num, string name, int);` so I can then use `ParameterIdentifierTuple` on a function, not a type, but the compiler said `bug1.d(5): Error: variable ``bug1.func`` cannot be declared to be a function`. Seems unreasonable given the implied semantics.
Re: std.traits.ParameterIdentifierTuple problem
On Saturday, 30 March 2024 at 21:51:34 UTC, Nick Treleaven wrote: On Saturday, 30 March 2024 at 21:45:34 UTC, Nick Treleaven wrote: On Saturday, 30 March 2024 at 21:25:45 UTC, Carl Sturtivant wrote: OK, so how can I get them? Am I forced to take that string and parse it with CTFE? Lookup the source of ParameterIdentifierTuple and change `FunctionTypeOf!func` to just `func` inside the first `static if`. Sorry, that actually doesn't work. I appreciate you actually having a shot at this! No apology necessary!
Re: std.traits.ParameterIdentifierTuple problem
On Saturday, 30 March 2024 at 21:07:35 UTC, Nick Treleaven wrote: On Saturday, 30 March 2024 at 19:23:07 UTC, Carl Sturtivant wrote: $ dmd -c bug1.d int(int num, string name, int) ["", "", ""] bug1.d(9): Error: static assert: "wrong!" ``` Please explain. How do I get the names of the identifiers out of a parameter list at compile time reliably? Although `.stringof` on a function type does include the parameter names, the names are not really part of the type - see: https://github.com/dlang/phobos/pull/3620#issuecomment-288469685 Perhaps `ParameterIdentifierTuple` should give a compile error when given a function type. OK, so how can I get them? Am I forced to take that string and parse it with CTFE?
std.traits.ParameterIdentifierTuple problem
Using the [ParameterIdentifierTuple](https://dlang.org/phobos/std_traits.html#ParameterIdentifierTuple) example just there, with one more step stops working. Details: ```D import std.traits; int foo(int num, string name, int); static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]); alias signature = typeof(foo); pragma(msg, signature.stringof); enum names = [ParameterIdentifierTuple!signature]; pragma(msg, names.stringof); static assert(names==["num","name",""], "wrong!"); ``` Output on compilation: ``` $ dmd --version DMD64 D Compiler v2.107.0 Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved written by Walter Bright $ dmd -c bug1.d int(int num, string name, int) ["", "", ""] bug1.d(9): Error: static assert: "wrong!" ``` Please explain. How do I get the names of the identifiers out of a parameter list at compile time reliably?
Re: Hidden members of Class objects
On Thursday, 7 March 2024 at 00:38:30 UTC, Richard (Rikki) Andrew Cattermole wrote: Yes its opt-in. https://dlang.org/spec/statement.html#synchronized-statement As you mentioned in another thread there's handy ABI documentation for classes and interfaces just here [https://dlang.org/spec/abi.html#classes](https://dlang.org/spec/abi.html#classes) that spells out the story.
Re: DFLAGS and DMD Windows
On Thursday, 21 March 2024 at 18:17:00 UTC, Carl Sturtivant wrote: On Wednesday, 20 March 2024 at 22:53:13 UTC, Carl Sturtivant wrote: Is it me, or does the [DFLAGS environment variable](https://dlang.org/dmd-windows.html#environment) have no effect on DMD. ``` dmd --version DMD64 D Compiler v2.107.0 ``` Anyone? Well, the docs are bogus. https://issues.dlang.org/show_bug.cgi?id=1660 Would have been nice if they'd mentioned this.
Re: ImportC GUID compilation problem with some Windows headers
On Thursday, 21 March 2024 at 22:33:17 UTC, Dave P. wrote: I filed a bug for this: https://issues.dlang.org/show_bug.cgi?id=24447 I haven’t tried on a windows box and this is just from me grepping through header files, but maybe try to `#define EXTERN_C` as nothing in the meantime? I'll give it a shot. Thanks for the bug report.
Re: DFLAGS and DMD Windows
On Wednesday, 20 March 2024 at 22:53:13 UTC, Carl Sturtivant wrote: Is it me, or does the [DFLAGS environment variable](https://dlang.org/dmd-windows.html#environment) have no effect on DMD. ``` dmd --version DMD64 D Compiler v2.107.0 ``` Anyone?
Re: ImportC GUID compilation problem with some Windows headers
On Thursday, 21 March 2024 at 00:06:56 UTC, Carl Sturtivant wrote: ```C EXTERN_GUID(IID_IBlahBlahBlah, 0xabcdef12, 0x11d2, 0xab3a, 0xc0, 0x4f, [...] ); ``` Has anyone successfully compiled an EXTERN_GUID declaration like this in a Windows header with ImportC using some C macro trickery for example?
ImportC GUID compilation problem with some Windows headers
I'm running into this COM related issue with some Windows headers, in the case when each GUID is declared in such a file as follows. ```C EXTERN_GUID(IID_IBlahBlahBlah, 0xabcdef12, 0x11d2, 0xab3a, 0xc0, 0x4f, [...] ); ``` and ImportC which is compiling `blah.c` containing only a few macro definitions and a single include of a header file say encounters these and responds with ``` [...] waffle.h(123): Error: variable `waffle.IID_IBlahBlahBlah` extern symbols cannot have initializers ``` Presumably MSVC simply compiles such files, but DMD's ImportC is too strict to do so. I've worked around this in some very dirty and inconvenient ways, but am hoping for a real solution of some kind. I want to use some of these IIDs and CLSIDs so I need to make these declarations work in some fashion. Inclusions are nested so these may be far from the header file I am including in `blah.c`. Any help appreciated.
Re: Need help with Windows linkage ( DMD using ImportC)
I found a way to make a solution for 64 bit Windows mechanically with many MSVC intrinsics, using only mingw64. Here's an [MSYS2](https://www.msys2.org/) bash script. ```bash gcc -E -P intrin.c -o vcintrinsics.c sed -i 's/extern __inline__ __attribute__((__always_inline__,__gnu_inline__))//g' vcintrinsics.c gcc -fPIC -shared -o vcintrinsics.dll vcintrinsics.c -Wl,--export-all-symbols -Wl,--output-def=vcintrinsics.def #lib -nologo -machine:x64 -def:vcintrinsics.def -out:vcintrinsics.lib dlltool -D vcintrinsics.dll -d vcintrinsics.def -l vcintrinsics.lib -m i386:x86-64 cp vcintrinsics.dll /c/D/dmd2/windows/bin64/ cp vcintrinsics.lib /c/D/dmd2/windows/lib64/ ``` The commented out line is using the MS librarian to do the same job as the mingw64 libtool. This script builds a dll containing 100+ intrinsics defined in mingw64 and makes an import library for DMD to use it from a developer command prompt. `intrin.c` contains only `#include ` and is preprocessed in the first line into `vcintrinsics.c` which if examined contains working definitions of many intrinsics but with `extern __inline__ __attribute__((__always_inline__,__gnu_inline__))` prefixing them, so they will not compile to actual library functions. The sed command strips those prefixes out, and the compilation makes a DLL containing the the intrinsics and a DEF file listing their names for linkage, ready for dlltool to assemble an import library suitable for DMD to link to so as to be able to dynamically link the DLL. And that's it; so far the result has just worked and I've had no linkage issues due to missing MSVC intrinsics since. I just put vcintrinsics.lib on the end of the dmd command line whenever I'm using real Windows headers in ImportC and the linker has always been satisfied so far. When I'm done, I can remove vcintrinsics from the dmd command line, and find out which intrinsics are actually needed for linking, and using the technique earlier in the thread above, satisfy those directly, so the result doesn't need vcintrinsics.dll. Hopefully DMD will soon know about these MSVC intrinsics but until then this is an effective way to more-or-less permanently work around the inevitable linkage problems.
DFLAGS and DMD Windows
Is it me, or does the [DFLAGS environment variable](https://dlang.org/dmd-windows.html#environment) have no effect on DMD. ``` dmd --version DMD64 D Compiler v2.107.0 ```
Re: Need help with Windows linkage ( DMD using ImportC)
On Thursday, 7 March 2024 at 18:14:32 UTC, Gregor Mückl wrote: 2. C code referring to MSVC-specific compiler intrinsics. At least InterlockedExchangeAdd, InterlockedExchangeAdd64 and _stosb are such intrinsics. This is harder to resolve. There are two ways forward here: either implement a shim function that replicates the intrinsic's functionality if possible or add support for these intrinsics to DMD. Thanks for the explanation, on the strength of which I found a way to deal with this correctly. I made `intrinsics1.c` that has `#include ` and contains an actual function for each missing intrinsic; e.g. for the missing __shiftright128 it has ```C unsigned __int64 D__shiftright128( unsigned __int64 LowPart, unsigned __int64 HighPart, unsigned char Shift ) { return __shiftright128(LowPart, HighPart, Shift); } ``` where I got the prototypes from this [list of intrinsics](https://learn.microsoft.com/en-us/cpp/intrinsics/alphabetical-listing-of-intrinsic-functions?view=msvc-170). Compiling this with MSVC `cl -c intrinsics1.c` produces a COFF object `intrinsics1.obj` containing an actual function to link to for each intrinsic. So this stage writes the code so we don't have to. As a matter of necessity, the names of the functions in `intrinsics1.c` representing the MSVC intrinsics are not the same as their actual names. By my convention above they are prefixed with "D". Now we could simply write an extern(C) D function in a module say `vcintrinsics.d`, that has exactly the intrinsic's name, and calls the "D" prefixed function linked from `intrinsics1.obj`, e.g. for the above example `vcintrinsics.d` could contain ```D extern(C): extern ulong D__shiftright128(ulong LowPart, ulong HighPart, ubyte Shift); ulong __shiftright128(ulong LowPart, ulong HighPart, ubyte Shift){ return D__shiftright128(LowPart, HighPart, Shift); } ``` As DMD doesn't know of these intrinsics, it won't complain about defining a function with exactly the same name as an intrinsic so as to implement that intrinsic as an actual function, solving the problem. `dmd -lib vcintrinsics.d intrinsics1.obj` then produces a library that resolves the linkage issue. An alternative not involving having two function calls to implement an intrinsic is to compile `intrinsics1.c` with MSVC into a DLL, and using a DEF file that renames the exports just like part of the solution [here](https://forum.dlang.org/post/ruupyklfkrvnjtker...@forum.dlang.org) make those functions available under their original names when linking to its import library. A lot of both of the above is boilerplate and can be automated. It would be even nicer if the MSVC tools could be persuaded to proceed in a similar way with DEF file renaming when building a static library, but I have not succeeded in making this happen. Anyone?
Re: DMD windows and Clang's llvm-link.exe
On Sunday, 10 March 2024 at 04:22:20 UTC, Richard (Rikki) Andrew Cattermole wrote: On 10/03/2024 4:46 PM, Carl Sturtivant wrote: suggesting that there's a reason version 9 instead of 17 of lld is being used in the latest DMD installation, that may be relevant what I'd like to try. Any idea what that might be? Yes, nobody has updated it. https://github.com/dlang/installer/blob/50f5825e9d9bf44afb9108f0c1a01a8038d2f156/.github/workflows/build_windows.yml#L22 The ldc one should match whatever LLVM is which is newer. No technical reason then, I assume you mean.
Re: DMD windows and Clang's llvm-link.exe
On Saturday, 9 March 2024 at 22:07:05 UTC, Richard (Rikki) Andrew Cattermole wrote: lld is used and distributed with dmd and ldc. That is known to work. If you have MSVC, it'll prefer that however. Interesting, perhaps I should have known that, though I have not used DMD on Windows for many years until now. I have this from a 64-bit "Developer Command Prompt": ``` lld-link --version LLD 9.0.0 (https://github.com/dlang/installer d4266cf3dccfd7a7d361d28143f86e98b2da8db8) dmd --version DMD64 D Compiler v2.107.0 Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved written by Walter Bright ``` Whereas from an MSYS2 Clang64 terminal I have this: ``` $ lld-link --version LLD 17.0.6$ clang --version clang version 17.0.6 ``` suggesting that there's a reason version 9 instead of 17 of lld is being used in the latest DMD installation, that may be relevant what I'd like to try. Any idea what that might be?
DMD windows and Clang's llvm-link.exe
I'd like to see if I can get dmd to work correctly with Clang rather than MS tools. Can anyone share any experience they've had with this or any understanding of the situation?
Re: Need help with Windows linkage ( DMD using ImportC)
On Thursday, 7 March 2024 at 18:14:32 UTC, Gregor Mückl wrote: 1. Missing import libraries for Win32 API functions. Anything starting with `__imp_` is a symbol that should be provided by a DLL import library. MapViewOfFileNuma2 for example is provided by onecore.lib in the Windows SDK, according to Microsoft documentation. Onecore: not sure what I did to add that dependency. Two symbols there. Thanks for the __imp_ clue. 2. C code referring to MSVC-specific compiler intrinsics. At least InterlockedExchangeAdd, InterlockedExchangeAdd64 and _stosb are such intrinsics. This is harder to resolve. There are two ways forward here: either implement a shim function that replicates the intrinsic's functionality if possible or add support for these intrinsics to DMD. Yes, not sure what the potential consequences are for my dirty replacement. Presumably DMD itself won't generate code using these, but ...
Re: Hidden members of Class objects
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?
Hidden members of Class objects
I notice that a class with no data members has a size of two words (at 64 bits). Presumably there's a pointer to a table of virtual functions, and one more. Is the Vtable first? A COM class that inherits from IUnknown and has no data members has a size of three words, presumably as before plus something that ordinarily is in the Vtable but can't be for a COM object as it has its own layout of that. What is actually in these objects using that space?
Re: Need help with Windows linkage ( DMD using ImportC)
On Monday, 4 March 2024 at 21:21:20 UTC, Carl Sturtivant wrote: ``` blah.obj: error LNK2019: unresolved external symbol _mul128 referenced in function MultiplyExtract128 blah.obj: error LNK2019: unresolved external symbol __shiftright128 referenced in function MultiplyExtract128 blah.obj: error LNK2019: unresolved external symbol _umul128 referenced in function UnsignedMultiplyExtract128 blah.obj: error LNK2019: unresolved external symbol __stosb referenced in function RtlSecureZeroMemory blah.obj: error LNK2019: unresolved external symbol __readgsqword referenced in function NtCurrentTeb blah.obj: error LNK2019: unresolved external symbol __imp_MapViewOfFileNuma2 referenced in function MapViewOfFile2 blah.obj: error LNK2019: unresolved external symbol __imp_CharUpperW referenced in function ua_CharUpperW ``` I forced linkage of these unused symbols as follows, but it would be nice to have a clean way to proceed. ```D extern(C) { int _InterlockedExchangeAdd(int* Addend, int Value) { return 0; }; long _InterlockedExchangeAdd64(long* Addend, long Value) { return 0; } void _mul128() {}; void __shiftright128() {}; void _umul128() {}; void __stosb() {}; void __readgsqword() {}; void __imp_MapViewOfFileNuma2() {}; void __imp_CharUpperW() {}; } ``` I got the D signatures of the first two so as to generate the correct linkage by using ImportC to translate the inclusion of `Windows.h` into a .di file, and searching.
Re: Using ImportC to augment a big C project with D
On Tuesday, 20 February 2024 at 18:33:42 UTC, Carl Sturtivant wrote: 1. When the resulting executable runs it will have D call C which in turn calls D. In that last D (the D files replacing some C files), if I throw an exception and don't catch it in the D files that replace some C files, will it propagate correctly to the D main function where I can catch it? My understanding is that [this reply](https://forum.dlang.org/post/ur5g46$fmb$1...@digitalmars.com) indicates that this works. Exceptions thrown by D can be caught by D in general in the presence of ImportC. 2. The C source calls exit() from C's stdlib, and D needs to terminate properly. Throwing an exception and catching it in D's main function seems to be a way to achieve this. What is the best way to deal with exit() ? So I can simulate C's exit() by throwing an exception and catching it in main() as [suggested here](https://forum.dlang.org/post/mailman.5856.1600355565.31109.digitalmars-d-le...@puremagic.com). 3. I want to use D's remarkable Fiber class to reimplement a deterministic stack changing context switch that in the original project is achieved with assembly code on a per-platform basis. This will mean that D's main function will call C which will call D which will effect a context switch. Is there any reason to believe this will work as naively hoped? I'll have to proceed experimentally, but I'd like to know in advance if this is doomed. Anyone?
Re: Using ImportC to augment a big C project with D
On Wednesday, 21 February 2024 at 12:45:50 UTC, Bastiaan Veelo wrote: What do you mean by "need"? You can call https://dlang.org/phobos/core_stdc_stdlib.html#.exit from D: Of course, but does it respect D shutdown? Output: ``` onlineapp._sharedStaticDtor_L11_C1 ``` So it does run module destructors, but not `scope(exit)` statements (which probably makes sense). So it doesn't respect D shutdown, i.e. what happens when returning from main with an error code. I would expect `exit()` called from the C source to have similar results. Why is that? I just found this. [Proper way to exit with specific exit code?](https://forum.dlang.org/thread/bavfkowjjcijeshrt...@forum.dlang.org)
Using ImportC to augment a big C project with D
I just saw the announcement that macros with parameters are now translated into D by ImportC. Incredible! Congratulations to all involved. As an occasional D user, I have long wanted a fast route to using D with an existing large C project (100K lines approximately). I want to replace the C main program with a D main function that calls the old C main function (suitably renamed) to change the command line arguments that can be supplied, and with the helpful side effect that druntime is properly initialized. I want to replace some C files with D ones. (I am cognizant of GC issues here, this is not what I am asking about.) Now I can use ImportC with all of the header files to make the D replacement files easy to write correctly. Perhaps I can use ImportC for all of the C source. 1. When the resulting executable runs it will have D call C which in turn calls D. In that last D (the D files replacing some C files), if I throw an exception and don't catch it in the D files that replace some C files, will it propagate correctly to the D main function where I can catch it? 2. The C source calls exit() from C's stdlib, and D needs to terminate properly. Throwing an exception and catching it in D's main function seems to be a way to achieve this. What is the best way to deal with exit() ? 3. I want to use D's remarkable Fiber class to reimplement a deterministic stack changing context switch that in the original project is achieved with assembly code on a per-platform basis. This will mean that D's main function will call C which will call D which will effect a context switch. Is there any reason to believe this will work as naively hoped?
Re: std.uni.CodepointSet from range of pairs of integers
On Monday, 19 February 2024 at 04:47:07 UTC, Richard (Rikki) Andrew Cattermole wrote: On 19/02/2024 5:33 PM, Carl Sturtivant wrote: On Monday, 19 February 2024 at 01:42:03 UTC, Richard (Rikki) Andrew Cattermole wrote: Indeed, nothing in that function body would suggest it needs to be a forward range. Ah yup, the body was changed but never updated its template conditional. https://github.com/dlang/phobos/commit/c9f1c42ed3a8bb92e48bf400ce2f31f434a99905 Thank you for looking into this.
Re: std.uni.CodepointSet from range of pairs of integers
On Monday, 19 February 2024 at 01:42:03 UTC, Richard (Rikki) Andrew Cattermole wrote: I can understand ``pure``. https://github.com/dlang/phobos/blob/master/std/uni/package.d#L2075 It is literally on the constructor. I should have noticed this!
Re: std.uni.CodepointSet from range of pairs of integers
On Monday, 19 February 2024 at 01:42:03 UTC, Richard (Rikki) Andrew Cattermole wrote: I can understand ``pure``. https://github.com/dlang/phobos/blob/master/std/uni/package.d#L2075 It is literally on the constructor. Now @safe I don't know. My best guess would be for some reason the constructor is getting inferred as it (templates get inferred). What about needing a forward range, not just an input range? It would seem it just needs to iterate through a sequence of pairs of integers.
std.uni.CodepointSet from range of pairs of integers
I wanted to construct a CodepointSet from a string, so I used the constructor here. https://dlang.org/phobos/std_uni.html#.InversionList.this.2 I wrote a range of pairs (CodepointIntervals) of integers consisting of each codepoint in the string paired with that plus one. This did solve the problem, but only after I overcame some peculiarities of the situation. Specifically, this required a forward range, not just an input range, so I wrote a save method. Once I fixed that problem, it needed empty() and popFront() to be pure. So I added the word pure to each in my range. Once I fixed that problem, it required those to be @safe, so I added that to my struct declaration of my range. Then everything worked. Could I have anticipated any of this, and what is the reason for each of these?
Re: std.uni CodepointSet toString
On Wednesday, 7 February 2024 at 17:11:30 UTC, H. S. Teoh wrote: Do we know why the compiler isn't getting it right? Shouldn't we be fixing it instead of just turning off elision completely? This matter seems to have been an issue for some time. https://forum.dlang.org/post/l5e5hm$1177$1...@digitalmars.com
Re: std.uni CodepointSet toString
On Wednesday, 7 February 2024 at 11:49:20 UTC, Richard (Rikki) Andrew Cattermole wrote: ``` undefined reference to `_D4core9exception__T15__switch_errorTZQsFNaNbNiNeAyamZv' collect2: error: ld returned 1 exit status Error: linker exited with status 1 ``` Use ``-allinst``, that is a template emission bug. ! Thanks, at least I can continue now, though presumably the cure has its own problems. ``` $ dmd --help | grep allinst -allinst generate code for all template instantiations ``` Unclear exactly how -allinst does this, given type parameters, and it will affect all of the many templates I use in source with CodepointSet. Can you shed any light?
std.uni CodepointSet toString
Need help working around a linkage problem. ```d import std.uni, std.conv, std.stdio, std.format; void main() { //auto c1 = unicode.InBasic_latin; auto c1 = CodepointSet('a','z'+1); writeln(c1.to!string); writeln(format("%d", c1)); writeln(format("%#x", c1)); writeln(format("%#X", c1)); writefln("%s", c1); } ``` doesn't link, but does link with the commented out CodepointSet instead. Combines code from these examples at the following URLs. https://dlang.org/phobos/std_uni.html#InversionList https://dlang.org/phobos/std_uni.html#.InversionList.toString ``` $ dmd --version DMD64 D Compiler v2.107.0 Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved written by Walter Bright $ dmd cset2.d /usr/bin/ld: cset2.o: in function `_D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv': cset2.d:(.text._D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv[_D4core8internal7switch___T14__switch_errorZQrFNaNbNiNfAyamZv]+0x19): undefined reference to `_D4core9exception__T15__switch_errorTZQsFNaNbNiNeAyamZv' collect2: error: ld returned 1 exit status Error: linker exited with status 1 ```
Re: Scripting with Variant from std.variant: parameter passing
On Friday, 2 February 2024 at 20:58:12 UTC, Paul Backus wrote: Another variation on the same theme: ```d /// map over a variadic argument list template mapArgs(alias fun) { auto mapArgs(Args...)(auto ref Args args) { import std.typecons: tuple; import core.lifetime: forward; import std.meta: Map = staticMap; auto ref mapArg(alias arg)() { return fun(forward!arg); } return tuple(Map!(mapArg, args)); } } import std.variant: Variant; import std.meta: allSatisfy; enum isVariant(T) = is(T == Variant); auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args)) { return .foo(mapArgs!Variant(args).expand); } ``` Thanks, will study the library machinery you used here.
Re: Scripting with Variant from std.variant: parameter passing
On Friday, 2 February 2024 at 19:22:22 UTC, Steven Schveighoffer wrote: ```d void foo(Variant x, Variant y) { ... } import std.meta : allSatisfy; enum isVariant(T) = is(T == Variant); // this is going to suck at CTFE but... string argsAsVariants(size_t count) { import std.format; import std.range; import std.alglorithm; import std.array; return iota(count).map!(i => format("Variant(args[%s])", i).join(","); } // shim auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args)) { mixin("return foo(", argsAsVariants(args.length), ");"); } ``` Thanks for this idea. I'll work on it. -Steve
Scripting with Variant from std.variant: parameter passing
It seems I cannot pass e.g. an int argument to a Variant function parameter. What's the simplest way to work around this restriction?
Re: import locality with function parameters
On Friday, 2 February 2024 at 01:23:11 UTC, Steven Schveighoffer wrote: Are you thinking of this? https://dlang.org/phobos/object.html#.imported -Steve Yes! Glad it's now part of D. Thank you.
import locality with function parameters
Hello, I seem to recall that there is surprising template to import a module and get a type from it inside the declaration of the type of a parameter to a function, so that the module need not be imported outside of the function definition. I think there was a blog article some years ago about this where there was some indication that this or something with equivalent effect would be incorporated into D in some way. How do I define a function with a parameter that is a type in an outside module while keeping module import local to that definition?
Re: compute from a string the text of a string literal
On Wednesday, 17 January 2024 at 18:53:48 UTC, Paul Backus wrote: There's a function that does this in Phobos, but it's `private`. Currently, the only way to access it is by calling `to!string` or `format` on a range that contains the string you want to convert as an element: ```d void main() { import std.range, std.conv, std.stdio; string s = `"foo"\bar`; string escaped = only(s).to!string[1 .. $-1]; // slice off [ and ] writeln(escaped); // "\"foo\"\\bar" } ``` Great! I'll use that!
compute from a string the text of a string literal
Hello, I'd like a function like this, ``` string image(string s) ``` that maps any string s into the doubly quoted backslash escaped text that would be a string literal for s were it pasted into a program. Perhaps with a second parameter with detailed options. Is there something out there I could use?
Re: Anyway to achieve the following
On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote: Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: [...] What you are asking for are reference variables. C++ has them: the example here illustrates the behavior you want. https://www.geeksforgeeks.org/references-in-c/ D does not have them, as mentioned above: https://forum.dlang.org/post/mailman.2714.1628875187.3446.digitalmars-d-le...@puremagic.com So to get the behavior you want, they have to be simulated, which is what this does: https://forum.dlang.org/post/lcrrnszslpyazoziy...@forum.dlang.org Next version: no `toString` and storage passed in by reference rather than by pointer. ``` struct S { int x = 1234; } void main() { import std.stdio; S s; auto p = &s.x; //construction of a using &(s.x) auto a = Ref!(int)(*p); //auto a = Ref!(int)(s.x); writeln(a); //displays 1234 s.x += 1; writeln(a); //displays 1235 a += 1; writeln(s.x); //displays 1236 } struct Ref(T) { T* ptr; this(ref T x) { ptr = &x; } @property ref T var() { return *ptr; } alias var this; } ``` I see no way to avoid overhead, as I see no simpler simulation.
Re: Anyway to achieve the following
``` struct S { int x = 1234; } void main() { import std.stdio; S s; //construction of a using &(s.x) auto a = Ref!(int)(&s.x); writeln(a); //displays 1234 s.x += 1; writeln(a); //displays 1235 a += 1; writeln(s.x); //displays 1236 } struct Ref(T) { T* ptr; this(T* p) { ptr = p; } string toString() { import std.conv; return to!string(*ptr); } ref T var() { return *ptr; } alias var this; } ```
Re: alias restriction??!
On Monday, 20 July 2020 at 17:24:56 UTC, Carl Sturtivant wrote: Well perhaps you do parse a "constant-offset expression" i.e. syntactically dotted with constant indexes, like name1.name2[constant].name3 and then later there's a semantic check that the "constant-offset expression" involves no indirections when an offset into the top level object is computed. Then it's treated like any other attribute of a struct with a known offset. Perhaps this could also work for a class at the top with recursively embedded structs and value arrays.
Re: alias restriction??!
On Sunday, 19 July 2020 at 20:46:19 UTC, Steven Schveighoffer wrote: On 7/19/20 4:21 PM, Carl Sturtivant wrote: Perhaps what's needed is something more that is less than allowing aliases for expressions in the wide sense you suggest here. I agree. Something not yet mentioned is that aliases provide direct access to the symbols for the purposes of looking at attributes -- something that a wrapper function doesn't provide. The question is: how do you restrict it to explicit data items within a specific aggregate without parsing arbitrary expressions? Well perhaps you do parse a "constant-offset expression" i.e. syntactically dotted with constant indexes, like name1.name2[constant].name3 and then later there's a semantic check that the "constant-offset expression" involves no indirections when an offset into the top level object is computed. Then it's treated like any other attribute of a struct with a known offset.
Re: alias restriction??!
On Sunday, 19 July 2020 at 17:06:14 UTC, Paul Backus wrote: Also, letting aliases refer to expressions essentially allows AST macros in through the back door. Consider the following example: [...] Perhaps what's needed is something more that is less than allowing aliases for expressions in the wide sense you suggest here.
Re: alias restriction??!
On Sunday, 19 July 2020 at 12:08:07 UTC, Paul Backus wrote: On Saturday, 18 July 2020 at 18:46:16 UTC, Carl Sturtivant wrote: Here's a toy version of a problem in the wild. struct S { long first; union T { long one; double two; } T second; alias First = first; alias Second = second.one; } void main() { S x; x.First = 4; x.Second = 5; // compilation error: "Error: need this for one of type long" } Easiest workaround: ref inout(long) Second() inout { return second.one; } Was trying to avoid this for performance reasons. In fact what are the performance implications of this sort of thing with current implementations? --- relative to using a simple offset.
alias restriction??!
Here's a toy version of a problem in the wild. struct S { long first; union T { long one; double two; } T second; alias First = first; alias Second = second.one; } void main() { S x; x.First = 4; x.Second = 5; // compilation error: "Error: need this for one of type long" } Second is a fixed offset into an S and it would be nice to have a name for it. Why doesn't alias know it's OK? I can work around this with some duplication as follows. struct S { long first; union { long one; double two; union T { long one; double two; } T second; } alias First = first; alias Second = one; } void main() { S x; x.First = 4; x.Second = 5; x.second.one = 6; import std.stdio; writeln(x); writeln(x.one); writeln(x.Second); } Is there any way to avoid the duplication of the entries in the anonymous union, aside from using a mixin template? Is there some other way (not involving writing a function) to work around this?
Re: How do I display unicode characters in D on standard (english) Windows 10 console window?
On Monday, 29 July 2019 at 22:17:55 UTC, WhatMeWorry wrote: This is a very stupid question but from Ali's book, I took this segment: writeln("Résumé preparation: 10.25€"); writeln("\x52\ésum\u00e9 preparation: 10.25\€"); and after running it all I get is the following: R├⌐sum├⌐ preparation: 10.25Γé¼ R├⌐sum├⌐ preparation: 10.25Γé¼ I was expecting the symbol "£" or something like that. What am I missing? In my Windows 10 build 1803 I was able to find a box to check to globally use the UTF-8 code page. Checking it requires a restart as it says the locale has changed. Settings>Time&Language>Region&Language>Administrative_Language_Settings brings up a Region dialog, and clicking on "Change system locale..." brought up a dialog where this box can be checked. After doing this the console acted sensibly right away with the code you wrote.
Re: opDispatch doesn't play nice with inheritance
On Thursday, 15 November 2018 at 19:01:45 UTC, Ali Çehreli wrote: On 11/15/2018 09:14 AM, Carl Sturtivant wrote: > opDispatch is special in that it allows for functions to be added to a > class or struct when undefined overtly but used elsewhere but it seems > those functions sadly are final. > > Can anything useful be done to remedy the situation? For the compiler to be able to make all opDispatch instantiations virtual, it would have to first see all calls that generate opDispatch instantiations. (Impossible in the presence of separate compilation.) Only then the compiler would know how large the vtbl of the base class should be and what member functions of the derived class are overrides of those virtual functions. I suppose it's such administrative difficulties that led to D defining anything that might conceivably be overridden to be virtual, whether or not actually overridden.
Re: opDispatch doesn't play nice with inheritance
On Thursday, 15 November 2018 at 18:04:42 UTC, Adam D. Ruppe wrote: Right, all templates are final, including opDispatch. What I've done in the past is to forward them to a virtual function with runtime arguments instead of compile time arguments. Kinda like: void opDispatch(string name)() { callMethod(name); } /* virtual */ void callMethod(string name) { // do a reflection loop or associate array or switch or whatever to dispatch it here, reimplemented (or at least re-mixed-in) in the child classes to account for their new methods } What exactly do you need to do with it? Maybe you can do an alternative design. Well, I found an alternative design not using opDispatch, not fundamentally dissimilar to what you suggested above, thanks for that, and it's not too uneconomical in its textual organization. I was hoping to avoid doing any of my own dispatching when inheritance would do it for me.
opDispatch doesn't play nice with inheritance
//Consider this: import std.stdio; void main() { X obj = new Y; writeln( obj._f() ); } class Proxy { X x; this(X x) { this.x = x; } string _f() { return "Proxy._f called"; } } class X { auto opDispatch(string f, Args...)(Args args) { Proxy p = new Proxy(this); return mixin("p."~f~"(args)"); } } class Y : X { string _f() { return "Y._f called"; } } // Presumably the presence of obj._f()in main causes the compilation of a function _f() in the class X, yet the function _f() in Y that inherits it merely shadows it; the keyword override cannot be used for this function. opDispatch is special in that it allows for functions to be added to a class or struct when undefined overtly but used elsewhere but it seems those functions sadly are final. Can anything useful be done to remedy the situation?
Re: custom sorting of lists ?
On Friday, 19 October 2018 at 17:53:58 UTC, Stanislav Blinov wrote: On Friday, 19 October 2018 at 17:40:59 UTC, Carl Sturtivant wrote: If we imagine an Ordered Range being a finite Range of some kind with the additional property that its values are ordered (--- exact definition needed ---)... There's already a SortedRange: https://dlang.org/phobos/std_range.html#.SortedRange That's nice. So perhaps all this can be done in using the existing machinery in Phobos.
Re: custom sorting of lists ?
On Wednesday, 17 October 2018 at 19:02:00 UTC, Steven Schveighoffer wrote: On 10/17/18 2:03 PM, Carl Sturtivant wrote: On Monday, 15 October 2018 at 13:39:59 UTC, Steven Schveighoffer wrote: But that's just the thing -- merge sort *does* depend on the container type. It requires the ability to rearrange the elements structurally, since you merge the sets of items together. This requires making another list from the original list, and ranges don't lend themselves to that. One thing you *can* do is allocate an array beside the original container, and move things back and forth. But this is not required if you have a linked-list type which can simply be restructured without moving. Doesn't this just mean a new special kind of range is needed to be defined? I don't think it fits into range primitives. Basically, I need to rearrange one element from one place to another in O(1) time (and without actually moving/copying the data). This really just is a linked-list special feature. One thing to note is that in a range of T, this move has nothing to do with the T. -Steve If we imagine an Ordered Range being a finite Range of some kind with the additional property that its values are ordered (--- exact definition needed ---). And work with Ranges of Ordered Ranges, can't we then sort by starting with a Range of single element Ranges (which are automatically ordered), and then pairwise merge repeatedly, i.e. get the next two elements (which are ordered ranges) and merge them & repeat, producing a Range of Ordered Ranges with half as many elements --- this is what I meant by pairwise merging --- and apply that pairwise merge repeatedly to the original range. I'm speculating intuitively, but it does look like there exists a possible extension of the notion of Range that would do the job.
Re: custom sorting of lists ?
On Monday, 15 October 2018 at 13:39:59 UTC, Steven Schveighoffer wrote: But that's just the thing -- merge sort *does* depend on the container type. It requires the ability to rearrange the elements structurally, since you merge the sets of items together. This requires making another list from the original list, and ranges don't lend themselves to that. One thing you *can* do is allocate an array beside the original container, and move things back and forth. But this is not required if you have a linked-list type which can simply be restructured without moving. Doesn't this just mean a new special kind of range is needed to be defined?
std.process.pipeProcess stalls (linux)
A computationally intensive process run from the command line works fine, runs to completion after several minutes, writing a few hundred lines of text to standard output and creating, writing to and closing around 200 files of size around 20KB. Now run from std.process.pipeProcess and periodically tested for completion with tryWait interleaved with sleep everything seems fine for a while. htop reveals that one core is running this at 100% CPU, and the first 76 files appear one after another, but the 77th file is opened and nothing is written to it, and htop reveals that the CPU usage has dropped to zero, and yet the process is still running according to ps, and this continues indefinitely, no error message, no indication from tryWait that it is done. htop does not reveal at any point that memory use is even half of what is available. Previously with similar processes that are a somewhat scaled back version of the one that fails as above, there's been no difference between what happened at the command line and what's happening here. Any ideas or suggestions?
Re: Initialization of struct containing anonymous union
On Monday, 14 August 2017 at 15:11:35 UTC, Steven Schveighoffer wrote: On 8/14/17 10:57 AM, Carl Sturtivant wrote: On Monday, 14 August 2017 at 14:49:57 UTC, Steven Schveighoffer wrote: On 8/14/17 10:36 AM, Carl Sturtivant wrote: On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer wrote: I think what the docs mean is that as soon as an anonymous union is present, you can't initialize anything further than the first union field. I understood that, hence my remark that "this is not helpful". OK. I thought you meant that the documentation is not helpful enough to understand what it means. So it seems I am forced to assign explicitly to each member of the struct, an ugly process. What is a nice way to solve this problem? I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; } As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution. Sorry, I thought you meant to assign the fields manually outside an initializer function. I can print out such a struct using writeln, but can find no way to use that text cleaned up in source code to create such a struct. Is D completely deficient here? Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14}; I could do that, but again it would involve finding the 50 or 100 names and writing text that looks quite like the text of an assignment except using colon instead of equals. So just as long and ugly. Well, you only have to initialize the ones that aren't defaulted. So in some use cases, this is hugely beneficial. But it seems in your case, you want to intialize everything explicitly (but only one member from each union). Tried this, also works. Looks like you just have to name items after the unions (i.e. when you are skipping members). Ugly, but passable: struct mess { union { int i; string s; } double x; int z; } mess s = {99, x: 3.14, 5}; -Steve ! Agreed!
Re: Initialization of struct containing anonymous union
On Monday, 14 August 2017 at 14:49:57 UTC, Steven Schveighoffer wrote: On 8/14/17 10:36 AM, Carl Sturtivant wrote: On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer wrote: I think what the docs mean is that as soon as an anonymous union is present, you can't initialize anything further than the first union field. I understood that, hence my remark that "this is not helpful". OK. I thought you meant that the documentation is not helpful enough to understand what it means. So it seems I am forced to assign explicitly to each member of the struct, an ugly process. What is a nice way to solve this problem? I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; } As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution. Sorry, I thought you meant to assign the fields manually outside an initializer function. I can print out such a struct using writeln, but can find no way to use that text cleaned up in source code to create such a struct. Is D completely deficient here? Hm... have you tried named field initializers? mess m = { i: 99, x: 3.14}; I could do that, but again it would involve finding the 50 or 100 names and writing text that looks quite like the text of an assignment except using colon instead of equals. So just as long and ugly. I believe you could generate a constructor given the introspection of the fields themselves. Probably would be messy though. Probably worth investigating, though not handy when quickly writing a short one-off tool. Was hoping D would have a better way.
Re: Initialization of struct containing anonymous union
On Monday, 14 August 2017 at 14:24:40 UTC, Steven Schveighoffer wrote: I think what the docs mean is that as soon as an anonymous union is present, you can't initialize anything further than the first union field. I understood that, hence my remark that "this is not helpful". So it seems I am forced to assign explicitly to each member of the struct, an ugly process. What is a nice way to solve this problem? I think the only way to solve it is with a constructor: this(int ival, double xval) { i = ival; x = xval; } As I though I made clear, I don't want write assignments to each variable in a 50 or 100 member struct from a library when D could supply a better solution. I can print out such a struct using writeln, but can find no way to use that text cleaned up in source code to create such a struct. Is D completely deficient here?
Initialization of struct containing anonymous union
struct mess { union { int i; string s; } double x; } How do I cleanly initialize this, assuming it's i that I want to give an overt value to? The docs say "If there are anonymous unions in the struct, only the first member of the anonymous union can be initialized with a struct literal, and all subsequent non-overlapping fields are default initialized". This is not helpful. https://dlang.org/spec/struct.html#struct-literal The above is a toy example distilled from a real problem. The struct comes from a C library and is very long and contains several anonymous unions. The D declaration of the struct was made by someone else who made the library available to D. I printed out such a struct returned by a call to the library, and wanted to create my own from scratch. But it seems that I can't just copy what writeln printed and edit it into an initialization analogous to mess m = { 99, 3.14 }; with the above, because I just get the analog of Error: overlapping initialization for field i and s Error: cannot implicitly convert expression (3.14) of type double to string and the alternative more like what is printed by writeln, auto m = mess(99, 3.14); produces a similar error message. So it seems I am forced to assign explicitly to each member of the struct, an ugly process. What is a nice way to solve this problem?
Re: subtlety or bug?
Aha, https://dlang.org/spec/struct.html#struct-destructor says that An identity assignment overload is required for a struct if one or more of these conditions hold: * it has a destructor so this is the above condition coming into play.
subtlety or bug?
The following compiles and runs correctly. https://forum.dlang.org/post/tzwsohkcqrkqotbwn...@forum.dlang.org But if I add a destructor to the reference struct template as follows, it no longer compiles, and the complaints are not about the destructor. ``` ~this() { ptr = null; } ``` refsim.d(39): Error: generated function refsim.reference!int.reference.opAssign (reference!int p) is not callable using argument types (int) refsim.d(42): Error: generated function refsim.reference!int.reference.opAssign (reference!int p) is not callable using argument types (int) These are complaining about lines where reference!int variables are assigned integers. What's going on? Here's the code linked to above without the destructor that works. ``` struct reference(T) { T* ptr; this(ref T x) { ptr = &x; } import std.exception : enforce; ref T cnvrt() @property { enforce( ptr !is null); return *ptr; } ref T cnvrt(T x) @property { enforce( ptr !is null); return *ptr = x; } alias cnvrt this; } void main() { int i; auto ri = reference!int(i); auto ri2 = reference!int(ri); assert(ri.ptr==ri2.ptr); i = 99; assert(i==ri && i==ri2 && ri==ri2); ri = 100; assert(i==ri && i==ri2 && ri==ri2); ri2 = 101; assert(i==ri && i==ri2 && ri==ri2); } ```
Re: alias can't find symbol or can't use symbol
On Wednesday, 3 May 2017 at 09:04:07 UTC, Jonathan M Davis wrote: I believe that the core problem is that an alias declaration just aliases a symbol - i.e. it just creates a new name for the symbol. And as far as I can tell, alias n2 = x2.n; is actually equivalent to alias n2 = member.n; You get exactly the same error message if that change is made. It's a bit like how you can call a static function with an object rather than the struct/class(e.g. s.foo() instead of S.foo()). Similarly, if you turn n into a member function, then you get an error like q.d(20): Error: this for n needs to be type member not type outer It's just aliasing the function, not creating a delegate or doing a syntactic conversion. If it _were_ doing a syntactic conversion and just making it so that everywhere you see n2, it got changed to x.n, then I could see code like outer o; o.n2 = 5; working. But that's not how alias declarations work. They just create a new name for the symbol in the scope that they're declared. So, the symbol isn't tied to a particular instance, and you get the problem that you're having. The following works with outer2 o; o.n2 = 5; so it's not static, i.e. n2 is tied to the instance here. struct outer2 { int n; alias n2 = n; } So it seems reasonable to have better semantics for an embedded struct with alias_this.
Re: alias can't find symbol or can't use symbol
On Wednesday, 3 May 2017 at 09:04:07 UTC, Jonathan M Davis wrote: I believe that the core problem is that an alias declaration just aliases a symbol - i.e. it just creates a new name for the symbol. And as far as I can tell, alias n2 = x2.n; is actually equivalent to alias n2 = member.n; You get exactly the same error message if that change is made. It's a bit like how you can call a static function with an object rather than the struct/class(e.g. s.foo() instead of S.foo()). Similarly, if you turn n into a member function, then you get an error like q.d(20): Error: this for n needs to be type member not type outer It's just aliasing the function, not creating a delegate or doing a syntactic conversion. If it _were_ doing a syntactic conversion and just making it so that everywhere you see n2, it got changed to x.n, then I could see code like outer o; o.n2 = 5; working. But that's not how alias declarations work. They just create a new name for the symbol in the scope that they're declared. So, the symbol isn't tied to a particular instance, and you get the problem that you're having. alias this is a bit different, because it isn't really aliasing the symbol - rather it's telling the compiler about an implicit conversion. So, that arguably confuses things a bit, but for your example to work, normal alias declarations would need to do more than create a new name for a symbol, and as I understand it, they don't. Now, I totally agree that it would be nice if your example would work, and I think that I've run into this problem before in my own code, but aliases would have to work a bit differently than they curently do for it to work. It seems like a reasonable enhancement request to me, but I'm not sure what Walter's take on it would be. He has a tendancy to see things how the compiler would in cases like this and not necessarily how a typical programmer would, so it wouldn't surprise me if he's reaction were that of course it wouldn't work, but I don't know. It's often the case that what the programmer thinks is intuitive doesn't really jive with how the language actually works. Thanks, that was enlightening. That said, if alias this really did bring n into the outer scope in the specific case when it's a variable in an embedded struct then `alias n2 = n` in the outer scope would work in the ordinary way. After all, struct fakeOuter { int n; alias n2 = n; } void main() { fakeOuter o; o.n2 = 5; } compiles and runs fine. And presumably as it's a struct being embedded here struct member { int n; } struct outer { member x; alias x this; //alias n2 = n; } the binary layouts of fakeOuter and outer are the same, so the rename is harmless because it has a simple interpretation in regular D without `alias this`.
Re: alias can't find symbol or can't use symbol
On Sunday, 30 April 2017 at 02:19:29 UTC, bauss wrote: What exactly did you expect here? 'n' is not in the scope of 'outer'. 'n' is in the scope of 'member'. Of course it works with 'x.n' since 'x' points to the 'member' declared inside 'outer'. I mean it would have worked with classes, but structs are different does not have any type of actual inheritance, which is what you're trying to achieve. ``` class member { int n; } class outer : member { alias n2 = n; // Ok ... } ``` It did NOT work with x.n as I asserted. And `alias x this` brings n into the scope of outer. So your reply makes no sense.
alias can't find symbol or can't use symbol
Consider the following. struct member { int n; } struct outer { member x; alias x this; alias n2 = n; } This does not compile: alias n2 = n; Error: undefined identifier 'n' On the other hand if change that into alias n2 = x.n; then it does compile. void main() { outer o; o.n2 = 5; } Now this code doesn't compile: o.n2 = 5; Error: need 'this' for 'n' of type 'int' Given that one struct inside another is a static situation, this seems unnecessarily strict. It's getting in the way of some name management with `alias this`. What's the rationale here?
Re: std.digest toHexString
On Thursday, 16 March 2017 at 18:51:45 UTC, Adam D. Ruppe wrote: Phobos could have been written to avoid this problem too, there's a few solutions that work, but right now, using the standard library in a way people expect to work will be silently disastrous. Yes, and as an outsider I find this, well, disconcerting. No complaint from the compiler about assignment to string of the result of a library function call should have produced a string with the obvious semantics. Having read this thread I have formed a conclusion. Implicitly slicing rvalue arrays is too much like implicitly taking the address of an rvalue. There's an explicit postfix operator [] to do that, and if there was no implicit slicing, I'd at least know where slicing is occurring and I wouldn't use the slice of a temporary beyond its lifetime. Now a function with a slice parameter could not be called with an rvalue array parameter without putting an explicit slice operator in at the point of call. But writing a function like that is just a way to regard rvalue arrays of different sizes based upon the same type as being the same type, when they are not. They are distinct types. And so a template could take care of that minor syntactic problem if so desired, with one instantiation for each rvalue array type (i.e. size), with a ref parameter to avoid copying. I see every reason to remove implicit slicing of rvalue arrays. Trying to keep it available sometimes is a complex endeavor, and the rules will be lengthy, and consequently have more complications to explain to people joining use of D, and for what? There's almost nothing to gain. This would be a mistake. D is already very large. If I didn't know what my general confidence level in D was for other reasons, this incident could well have driven me away. The standard library compiled completely unexpectedly insane and unsafe semantics when I just called a simple-looking function. This sort of thing is undoubtedly bringing D into disrepute with some people here and there, people just trying it out to solve a problem.
Re: std.digest toHexString
On Thursday, 16 March 2017 at 17:20:45 UTC, H. S. Teoh wrote: I'm not convinced casting static array to immutable is OK. Check this out: import std.stdio; char[32] func() { char[32] staticArr = "A123456789abcdefB123456789abcdef"; return staticArr; // OK, by-value return } string gunk() { string x = func(); // implicit conversion char[32] -> string writeln(x.ptr); writeln(x); // prints "A123456789abcdefB123456789abcdef" return x; } void main() { auto s = gunk(); writeln(s.ptr); // prints same address as in gunk() writeln(s); // prints corrupted string } Run this code and you'll see that s.ptr has the same address as x.ptr, and that x.ptr is the address of a local variable. This is blatantly wrong. Filed a new issue for this: https://issues.dlang.org/show_bug.cgi?id=17261 Exactly, if there was a variable of type char[32] on the right hand side of string x = func(); instead of the call of func, then the compiler would complain. So this is a bug.
Re: std.digest toHexString
On Thursday, 16 March 2017 at 17:18:30 UTC, Adam D. Ruppe wrote: On Thursday, 16 March 2017 at 17:12:08 UTC, Carl Sturtivant wrote: I did that, and it made no difference. :( wait a minute i just realized: toHexString.d(11) in the error message You named the file toHexString which means the *module* will be named toHexString by default... OK, right!
Re: std.digest toHexString
On Thursday, 16 March 2017 at 16:59:40 UTC, Adam D. Ruppe wrote: Yet the documentation says there's a toHexString that returns a string. Yes, indeed, it returns a string if it is passed a dynamic array. Ah, that's the distinction, should have noticed. Remember though, like I warned on my doc fork, overload resolution NEVER looks at the left hand side of the equation, it is always done on arguments alone. The stupid auto return stuff Phobos loves so much obscures it, but md5Of returns a ubyte[16]. That calls the first overload, the one that returns char[num*2] OK, but if I try to do this, char[2] u; string s = u; the compiler will complain: Error: cannot implicitly convert expression (u) of type char[2] to string. So why does it allow the template instantiation of return type char[num*2] in place of u above?
Re: std.digest toHexString
On Thursday, 16 March 2017 at 17:01:56 UTC, Adam D. Ruppe wrote: On Thursday, 16 March 2017 at 16:56:11 UTC, Carl Sturtivant wrote: "toHexString.d(11): Error: function expected before (), not module toHexString of type void" Module??? huh idk. use my search engine btw! http://dpldocs.info/toHexString it is in `std.digest.digest` but that should be publicly imported. I did that, and it made no difference. :(
Re: std.digest toHexString
On Thursday, 16 March 2017 at 16:21:08 UTC, Adam D. Ruppe wrote: If I replace md5Of(arg).toHexString() with toHexString(md5Of(arg)) That works for me though... maybe it is just a version mismatch or something, since toHexString is in a different module than md5of. I have this problem on Linux and Windows, at 64 bits on the former, and 32 on the latter, with simple clean installations of dmd 2.073.2 on Linux, 2.073.3 on Windows. Same error message. "toHexString.d(11): Error: function expected before (), not module toHexString of type void" Module???
Re: std.digest toHexString
On Thursday, 16 March 2017 at 16:21:08 UTC, Adam D. Ruppe wrote: On Thursday, 16 March 2017 at 16:13:33 UTC, Carl Sturtivant wrote: string ans = md5Of(arg).toHexString(); That is a major D design flaw biting you the same way it has bitten so many others. See the red box in my documentation fork: http://dpldocs.info/experimental-docs/std.digest.digest.toHexString.2.html toHexString returns a static array... on the stack. Then the stupid language not only implicitly casts it to immutable, it also implicitly slices it, giving you a reference to mutable, temporary data pretending to be permanent, immutable data. Silently cast to immutable without copying!??!! This is so wrong. Yet the documentation says there's a toHexString that returns a string. http://dlang.org/phobos/std_digest_digest.html#.toHexString I don't understand the overload resolution implied at this link. How is a toHexString selected in string ans = md5Of(arg).toHexString(); ?
std.digest toHexString
What's going on here? ``` import std.digest.md, std.stdio; void main() { string ans = hex("qwertyuiop"); writeln(ans); } string hex(string arg) { string ans = md5Of(arg).toHexString(); writeln(ans); return ans; } ``` This compiles, and when run writes out corrupt nonsense from the writeln in main, while just before that writing out 6EEA9B7EF19179A06954EDD0F6C05CEB from the function hex. If I replace md5Of(arg).toHexString() with toHexString(md5Of(arg)) it won't compile, claiming that "toHexString.d(11): Error: function expected before (), not module toHexString of type void". Yet the examples here http://dlang.org/phobos/std_digest_md.html use toHexString freely in this way. I thought I was using toHexString by UFCS, in the earlier example, but this appears to be untrue. The return from the function hex above somehow corrupts the string returned, suggesting deallocation is occurring in some fashion. So I replaced md5Of(arg).toHexString() with md5Of(arg).toHexString().dup and the problem vanished. Now 6EEA9B7EF19179A06954EDD0F6C05CEB is printed out twice.
Part of D available to run at compile time
is there documentation on which parts of D are available to compile time execution?
link to C++ function in a namespace whose name is a D keyword
Hello, From D I want to call e.g. /* C++ prototype */ namespace ns { int try(int x); } without writing a C or C++ wrapper. Presumably the following D doesn't work, because it doesn't mangle the name as if it's in the namespace ns. pragma(mangle, "try") extern(C++, ns) int try_(int x); So how to I get correct mangling here?
Re: link to C function whose name is a D keyword
On Wednesday, 6 January 2016 at 15:42:34 UTC, Adam D. Ruppe wrote: On Wednesday, 6 January 2016 at 15:41:27 UTC, Carl Sturtivant wrote: //D that doesn't work: extern(C) int try(int x); Try: pragma(mangle, "try") extern(C) int try_(int x); then call it with the udnerscore in D, the linker should tie it up thanks to the pragma. Very handy! Thank you.
link to C function whose name is a D keyword
Hello, Is there a way from D to do this, without writing a C wrapper? e.g. I want to call a C function named 'try'. /* C prototype */ int try(int x); //D that doesn't work: extern(C) int try(int x);
Re: DFLAGS ignored. How to get a dmd installation on windows that is 64 bit only
If you must force dmd to be only 64bit, use sc.ini file to do so and not rely on your environment variables. OK, why? (This does work, so thank you.) Also why do you not want 32-bit support? It's not like it won't work on a 64bit computer, it will. I've used 32-bit D and DMC a lot on real projects, so I am aware of this. I just want to tinker with the installation on a machine I use for that sort of thing, without worrying about the 32-bit configuration at all, and with no possibility of executing 32-bit tools.
DFLAGS ignored. How to get a dmd installation on windows that is 64 bit only
The docs for dmd for windows say that the DFLAGS environment variable's value will be appended to the dmd command line. I tried this with -m64 as the value and this is ignored. http://dlang.org/dmd-windows.html#environment More generally, is there a standard rearrangement of files and environment variables so that all compilation and linking is 64 bit, and 32-bit stuff is simply not there?
Re: cast(T) documentation
On Thursday, 5 November 2015 at 18:52:05 UTC, Ali Çehreli wrote: On 11/05/2015 07:51 AM, Carl Sturtivant wrote: Hello, Is cast(T) documented all in one place somewhere? I'd like to understand exactly what it does and does not do. This is what I can find: http://dlang.org/expression.html#CastExpression Ali Hello Ali, I probably should have found that! Thanks.
cast(T) documentation
Hello, Is cast(T) documented all in one place somewhere? I'd like to understand exactly what it does and does not do.
trouble compiling Fiber example code from docs dmd linux v2.067.1
I took the example code from here, http://dlang.org/phobos/core_thread.html#.Fiber and wrapped the statements at the bottom inside main() and put import core.thread and std.stdio at the top, and the compiler gave me the following. /usr/include/dmd/druntime/import/core/thread.d(3894): Error: static variable PAGESIZE cannot be read at compile time fiberexample.d(8):called from here: super.this(&this.run, PAGESIZE * 4LU) /usr/include/dmd/druntime/import/core/thread.d(3871): Error: static variable PAGESIZE cannot be read at compile time Help anyone?
Re: Seems core.thread.Fiber is broken dmd windows 64-bit build
http://forum.dlang.org/thread/md5kq0$8au$1...@digitalmars.com Got a working build at 64 bits using the 2.067 beta 3. Delighted.
Re: Seems core.thread.Fiber is broken dmd windows 64-bit build
IIRC there are some fixes to the Win64 context switching code in the 2.067 or master druntime. You might want to try those first before spending more time tracking this down. Great, and thanks.
Re: Seems core.thread.Fiber is broken dmd windows 64-bit build
On Monday, 9 March 2015 at 17:00:38 UTC, Jacques Müller wrote: With the newest beta everything seems to work fine. http://forum.dlang.org/thread/md5kq0$8au$1...@digitalmars.com That's great news! Thank you.
Re: Seems core.thread.Fiber is broken dmd windows 64-bit build
I can reproduce this issue with dmd 2.066.1, please go forward and open a issue on https://issues.dlang.org/ Kind Regards Benjamin Thaut Thank you; will do.
Re: Seems core.thread.Fiber is broken dmd windows 64-bit build
Please confirm or deny that this is a real bug, as its getting in the way of a genuine project. How should I proceed? I'm working on a 64-bit Windows port of the following. http://www.cs.arizona.edu/icon/ Here's the 32-bit Windows port. http://www.cs.arizona.edu/icon/v95w.htm Among other things I'm using D to implement Icon's coexpressions portably using core.thread.Fiber which works fine at 32 bits. They are implemented using pthreads on other platforms, though historically there used to be a platform dependent assembly code context switch, close to the way that core.thread.Fiber is implemented. The Fiber implementation is 20 times faster at 32 bits.
Seems core.thread.Fiber is broken dmd windows 64-bit build
The following crashes on Windows 7 sp1 64-bit edition when build at 64 bits with dmd and the Microsoft linker that comes with Windows SDK 7.1 (i.e. MSVC 2010 linker). I've had no trouble with other D code when using that arrangement, though I have not used threads. When built at 32 bits with dmd and optlink it runs fine. == import core.thread, std.stdio; void main() { writefln( "A pointer is %d bytes", (void*).sizeof); void f1() { writeln( 1); Fiber.yield(); writeln( 3); } auto fiber = new Fiber( &f1); fiber.call(); writeln( 2); fiber.call(); writeln( 4); } === The 64 bit version outputs 1 and crashes when yield is executed. Other tests reveal that yield is the problem. Should I be doing something special with linkage so this works? What is going on?
Re: core.thread.Fiber --- runtime stack overflow unlike goroutines
On Friday, 15 August 2014 at 20:11:43 UTC, Carl Sturtivant wrote: On Friday, 15 August 2014 at 08:41:30 UTC, Kagamin wrote: On Thursday, 14 August 2014 at 07:46:29 UTC, Carl Sturtivant wrote: The default size of the runtime stack for a Fiber is 4*PAGESIZE which is very small, and a quick test shows that a Fiber suffers a stack overflow that doesn't lead to a clean termination when this limit is exceeded. Pass a bigger stack size to the Fiber constructor? No good if the stack size needed depends dynamically on the computation in that Fiber. Should have read further down the thread --- you're right as the memory is in effect merely reserved virtual memory and isn't actually allocated.
Re: core.thread.Fiber --- runtime stack overflow unlike goroutines
On Friday, 15 August 2014 at 15:40:35 UTC, Sean Kelly wrote: On Friday, 15 August 2014 at 15:25:23 UTC, Dicebot wrote: No, I was referring to the proposal to supply bigger stack size to Fiber constructor - AFAIR it currently does allocate that memory eagerly (and does not use any OS CoW tools), doesn't it? I thought it did, but apparently the behavior of VirtualAlloc and mmap (which Fiber uses to allocate the stack) simply reserves the range and then commits it lazily, even though what you've told it to do is allocate the memory. This is really great news since it means that no code changes will be required to do the thing I wanted to do anyway. Just read this after posting earlier replies! Very exciting. I'll be doing some experiments to see how this works out. What about at 32-bits?
Re: core.thread.Fiber --- runtime stack overflow unlike goroutines
On Friday, 15 August 2014 at 08:41:30 UTC, Kagamin wrote: On Thursday, 14 August 2014 at 07:46:29 UTC, Carl Sturtivant wrote: The default size of the runtime stack for a Fiber is 4*PAGESIZE which is very small, and a quick test shows that a Fiber suffers a stack overflow that doesn't lead to a clean termination when this limit is exceeded. Pass a bigger stack size to the Fiber constructor? No good if the stack size needed depends dynamically on the computation in that Fiber.
Re: core.thread.Fiber --- runtime stack overflow unlike goroutines
On Thursday, 14 August 2014 at 18:52:00 UTC, Sean Kelly wrote: On 64 bit, reserve a huge chunk of memory, set a SEGV handler and commit more as needed. Basically how kernel thread stacks work. I've been meaning to do this but haven't gotten around to it yet. Very nice; the hardware VM machinery takes care of it and there's only overhead when overflow occurs. D's Fibers will really be something remarkable for user-space with this facility.
core.thread.Fiber --- runtime stack overflow unlike goroutines
The default size of the runtime stack for a Fiber is 4*PAGESIZE which is very small, and a quick test shows that a Fiber suffers a stack overflow that doesn't lead to a clean termination when this limit is exceeded. This makes it difficult to simulate deterministic alternation where the stack size needed is unpredictable because complex deterministic computations are going on inside Fibers. In contrast, the Go programming language's goroutines can extend their stacks as needed at runtime, and so can be used to simulate deterministic alternation without this limitation, and yet be initially executed with each having only a small stack size. There seems to be a claim that all that's needed to add D-routines (goroutines for D) is a scheduler and a Channel type, on top of Fiber. http://forum.dlang.org/thread/lphnen$1ml7$1...@digitalmars.com See the initial post, point 7., as well as supporting remarks in later replies. Am I missing something? Is there a clean and simple way to get Fiber to no longer suffer a stack overflow when implementing D-routines?
Re: D may disappoint in the presence of an alien Garbage Collector?
On Monday, 28 July 2014 at 20:52:01 UTC, Anton wrote: On Monday, 28 July 2014 at 19:57:38 UTC, Carl Sturtivant wrote: Suppose I want to use D as a system programming language to work with a library of functions written in another language, operating on dynamically typed data that has its own garbage collector, such as an algebra system or the virtual machine of a dynamically typed scripting language viewed as a library of operations on its own data type. For concreteness, suppose the library is written in C. (More generally, the data need not restricted to the kind above, but for concreteness, make that supposition.) Data in such a system is usually a (possibly elaborate) tagged union, that is essentially a struct consisting of (say) two words, the first indicating the type and perhaps containing some bits that indicate other attributes, and the second containing the data, which may be held directly or indirectly. Call this a Descriptor. Descriptors are small, so it's natural to want them held by value and not allocated on the heap (either D's or the library's) unless they are a part of a bigger structure that naturally resides there. And it's natural to want them to behave like values when passed as parameters or assigned. This usually fits in with the sort of heterogeneous copy semantics of such a library, where some of the dynamic types are implicitly reference types and others are not. The trouble is that the library's alien GC needs to be made aware of each Descriptor when it appears and when it disappears, so that a call of a library function that allocates storage doesn't trigger a garbage collection that vacuums up library allocated storage that a D Descriptor points to, or fails to adjust a pointer inside a D descriptor when it moves the corresponding data, or worse, follows a garbage pointer from an invalid D Descriptor that's gone out of scope. This requirement applies to local variables, parameters and temporaries, as well as to other situations, like D arrays of Descriptors that are D-heap allocated. Ignore the latter kind of occasion for now. Abstract the process of informing the GC of a Descriptor's existence as a Protect operation, and that it will be out of scope as an Unprotect operation. Protect and Unprotect naturally need the address of the storage holding the relevant Descriptor. In a nutshell, the natural requirement when interfacing to such a library is to add Descriptor as a new value type in D along the lines described above, with a definition such that Protect and Unprotect operations are compiled to be performed automatically at the appropriate junctures so that the user of the library can forget about garbage collection to the usual extent. How can this requirement be fulfilled? Suppose I want to do system programming...Would I choose the option with a GC ? Just get off. The GC is just such a fagot. People are smart enough to manage memory. It's the library to interface to that has its own GC, not my code. I just need to use D's system programming capabilities to work around the library's nasty GC so my data used by my calls to that library isn't trashed, and to do that efficiently and transparently. A system programming language should be able to efficiently interface to anything, right?
Re: D may disappoint in the presence of an alien Garbage Collector?
On Monday, 28 July 2014 at 21:33:54 UTC, Rene Zwanenburg wrote: If I understand you correctly, an easy way is to use RefCounted with a simple wrapper. Something like this: // Descriptor defined by the external library struct DescriptorImpl { size_t type; void* data; } // Tiny wrapper telling the alien GC of the existence of this reference private struct DescriptorWrapper { DescriptorImpl descriptor; alias descriptor this; @disable this(); this(DescriptorImpl desc) { // Make alien GC aware of this reference } ~this() { // Make alien GC aware this reference is no longer valid } } // This is the type you will be working with on the D side alias Descriptor = RefCounted!DescriptorWrapper; Just read RefCounted definition here, http://dlang.org/phobos/std_typecons.html#.RefCounted and it heap allocates its object, so your response above does not stack allocate the basic type that you call DescriptorWrapper, and is not a solution to the problem as stated. If there was no alien GC, but everything else was the same, heap allocation of something containing a DescriptorImpl would be unnecessary. Now achieve the same with the alien GC present without an extra layer of indirection and heap allocation --- this is the essence of my question.
Re: Linux Dynamic Loading of shared libraries
Can't retrieve the archive from that URL. britseyeview.com/plugin101.tar.bz2 Interested, so can you please fix? On Monday, 10 March 2014 at 11:59:20 UTC, Steve Teale wrote: On Sunday, 9 March 2014 at 12:07:22 UTC, Steve Teale wrote: Now suppose that my D shared library contains a class, rather that just module ctors/dtors, how do I go about creating an instance of that class and using its methods? After wandering down several dead-end paths, and help from other contributors, I have finally come up with something that looks like the basis of a plugin pattern for Linux DMD using shared objects (.so files). This is somewhat long for a forum post. You can download this readme and the associated files from britseyeview.com/plugin101.tar.bz2 To get started, you need a base class that provides declarations for all functions that the plugin will be allowed to use externally. Why base class, and not interface? Well I guess because interfaces don't provide any information about data. If you create a shared library based on an interface, then all the shared object methods that reference data in the class that implements the interface fail miserably. I'm sure someone will explain why - probably some obvious thing I have overlooked. OK, so my base class is: module plugin; class Plugin { int n; this(int _n) { n = _n; } int foo() { return int.min; } void bar() {} } The class that implements this base in the shared library is: module exta; import plugin; import std.stdio; import std.math; class ExtA: Plugin { double d; this(int n) { super(n); d = PI; } override int foo() { return ++n; } override void bar() { writefln("Done my thing (%f)", d); } } Plugin getInstance(int n) { return new ExtA(n); } shared static this() { writeln("exta.so shared static this"); } shared static ~this() { writeln("exta.so shared static ~this"); } The module ctor/dtor are included because that has become conventional in discussions about dynamic loading. Otherwise, the so has the class implementation - ExtA, and a shared method to create an instance of same. It includes references to methods in Phobos. The test program is as follows: module main; import core.runtime; import std.stdio; import plugin; extern(C) void* dlsym(void*, const char*); alias Plugin function(int) pfi; Plugin getPlugin(string name) { void* lib = Runtime.loadLibrary(name~".so"); if (lib is null) { writeln("failed to load plugin shared object"); return null; } void* vp = dlsym(lib, "_D4exta11getInstanceFiZC6plugin6Plugin\0".ptr); if (vp is null) { writeln("plugin creator function not found"); return null; } pfi f = cast(pfi) vp; Plugin x = f(42); if (x is null) { writeln("creation of plugin failed"); return null; } return x; } void main() { Plugin x = getPlugin("exta"); int n = x.foo(); writefln("n = %d", n); x.bar(); } The long symbol name used in the dlsym() call is of course from the .map file generated when the .so file is created These can be built using the following primitive makefile, whose main purpose is to spell out the required compiler flags: main : dmd -c plugin.d dmd -c -shared -fPIC exta.d dmd exta.o -shared -defaultlib=libphobos2.so -map dmd -c main.d dmd main.o plugin.o -L-ldl -defaultlib=libphobos2.so -L-rpath=. This assumes that the plugins will be in the same directory as the executable (rpath=.). Note that there is no call to Runtime.unloadLibrary(). The assumption her is that once the plugin has been loaded it will be there for the duration of the program. If you want to unload it you'll probably have to make sure the plugin object is purged from memory first, and I have not discovered how to do that yet ;=( Steve