Re: "only" vs "[]"
On Monday, 8 August 2022 at 11:35:48 UTC, pascal111 wrote: The output of next code is the same to extent that we feel that there's no difference between "only" and "[]", so what "only" added here?: '''D [1,2,3].writeln; only(1,2,3).writeln; ''' output: [1, 2, 3] [1, 2, 3] `only(1,2,3)` doesn't use GC. `[1,2,3]` allocate GC array.
Inferred attributes errors in template function.
Hello, I have this problem: ```d static int i; void bar(T)(){ static if(is(T == int)) (()@system => 1)(); static if(is(T == float)) i = 42; } void foo(T)(){ bar!T(); } void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` } ``` When template function foo is called and its inferred attributes are not compatible with attributes of main, errors are not really useful. Compiler print that foo!float is not pure or foo!int is not @safe but doesn't tell why. Is in dmd some flag that print errors similarly to this?: ```d void main()@safe pure{ foo!long(); foo!float(); //Error: `pure` function `D main` cannot call impure function `onlineapp.foo!float.foo` //Error: potentially `pure` function `onlineapp.foo!float.foo` cannot call impure function `onlineapp.bar!float.bar` //Error: potentially `pure` function `onlineapp.bar!float.bar` cannot access mutable static data `i` foo!int(); //Error: `@safe` function `D main` cannot call `@system` function `onlineapp.foo!int.foo` //Error: potentially `@safe` function `onlineapp.foo!int.foo` cannot call `@system` function `onlineapp.bar!int.bar` //Error: potentially `@safe` function `onlineapp.bar!int.bar` cannot call `@system` delegate `onlineapp.bar!int.bar.__lambda1` } ```
Re: mixin template
On Monday, 23 May 2022 at 15:14:53 UTC, Vindex wrote: I have this code: ``` import std.array, std.exception, std.stdio; mixin template RealizeException() { this(string msg, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line); } } class WrongUsage : Exception { mixin RealizeException; this(string[] messages, string file = __FILE__, size_t line = __LINE__) { auto msg = std.array.join(messages, "\n"); super(msg, file, line); } } void main() { throw new WrongUsage("Error message."); } ``` ... and this error: ``` mixin_exception.d(19): Error: constructor `mixin_exception.WrongUsage.this(string[] messages, string file = __FILE__, ulong line = cast(ulong)__LINE__)` is not callable using argument types `(string)` mixin_exception.d(19):cannot pass argument `"Error message."` of type `string` to parameter `string[] messages` Failed: ["/usr/bin/dmd", "-v", "-o-", "mixin_exception.d", "-I."] ``` Why? Why can't I have two constructors when I use mixin? If I replace mixin to real code, I have no problem: ``` class WrongUsage : Exception { this(string msg, string file = __FILE__, size_t line = __LINE__) { super(msg, file, line); } this(string[] messages, string file = __FILE__, size_t line = __LINE__) { auto msg = std.array.join(messages, "\n"); super(msg, file, line); } } ``` mixin template create scope, for example if it was normal function (no ctor), you can do this: ```d mixin template RealizeException() { static void foo(string){} } class WrongUsage{ mixin RealizeException x; alias foo = x.foo; static void foo(string[]){} } void main() { WrongUsage.foo("Error message."); } ``` But for ctor this doesn't work...
Re: Odd construct idea. Splitting arguments inside a parameter list.
On Monday, 23 May 2022 at 08:34:21 UTC, Chris Katko wrote: D struct pair { float x,y; } [...] This work too: ```d myFunction(taco, p.tupleof, burrito); ```
Re: decimal type in d
On Monday, 16 May 2022 at 09:59:41 UTC, bauss wrote: On Monday, 16 May 2022 at 09:46:57 UTC, IGotD- wrote: On Sunday, 15 May 2022 at 13:26:30 UTC, vit wrote: [...] This also something I wondered, it should be standard in the D library. Implementing it can be done straight forward with existing D language primitives, essentially a struct. For those who don't know, decimal in C# is like a floating point value but the exponent is a power of 10 (internally total 16 bytes). This means that for "simple" mathematics rational decimal values remains rational decimals values and not some rounded value that would happen if you would use normal floating point values. The decimal type is essential for financial calculations. I think D can more or less copy the C# solution. Here's the implementation if anyone needs it: https://referencesource.microsoft.com/#mscorlib/system/decimal.cs,1b2858baf311cbf9 Should be fairly straightforward to implement. Thanks, but it is not full implementation of decimal, arithmetic operator are missing. On Monday, 16 May 2022 at 16:41:33 UTC, Steven Schveighoffer wrote: On 5/15/22 9:26 AM, vit wrote: Hello, I want read decimal type from sql db, do some arithmetic operations inside D program and write it back to DB. Result need to be close to result as if this operations was performed in sql DB. Something like C# decimal. Exists this kind of library ind D? (ideally `pure @safe @nogc nothrow`). https://code.dlang.org/search?q=decimal -Steve Thanks, most of the packages are incomplete or too old (doesn't compile), but this one https://code.dlang.org/packages/decimal can by modified to work for my use.
decimal type in d
Hello, I want read decimal type from sql db, do some arithmetic operations inside D program and write it back to DB. Result need to be close to result as if this operations was performed in sql DB. Something like C# decimal. Exists this kind of library ind D? (ideally `pure @safe @nogc nothrow`).
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 11:58:15 UTC, zjh wrote: On Friday, 13 May 2022 at 08:28:56 UTC, vit wrote: ... ```d ... this(DataSources dataSources){ this.dataSources = dataSources; } ... return new MultiGraph!(staticMap!(PointerTarget, Ts))(ts);//ts ``` How is `ts` convert to `DataSources`? `ts` have same type like `DataSources`: ```d import std.meta : staticMap, allSatisfy; import std.traits : PointerTarget, isPointer; import std.conv : to; alias Pointer(T) = T*; class MultiGraph(Ts...){// Ts == (float, double, int) alias DataSources = staticMap!(Pointer, Ts); // (float, double, int) -> (float*, double*, int*) DataSources dataSources;// -> (float*, double*, int*) float[][DataSources.length] buffers;// -> float[][3] this(DataSources dataSources){ // dataSources == (float*, double*, int*) this.dataSources = dataSources; } void onTick() { //grab datasource data and do something. foreach(enum i, alias d; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto multiGraph(Ts...)(Ts ts) // Ts == (float*, double*, int*) if(allSatisfy!(isPointer, Ts)){ //all types in Ts are pointers alias DataSources = staticMap!(PointerTarget, Ts); // (float*, double*, int*) -> (float, double, int) return new MultiGraph!(DataSources)(ts); } void main(){ float myFloat; double myDouble; int myInteger; auto g = multiGraph(, , ); } ```
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 07:32:16 UTC, Chris Katko wrote: On Friday, 13 May 2022 at 07:05:36 UTC, vit wrote: On Friday, 13 May 2022 at 06:43:39 UTC, Chris Katko wrote: I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. [...] I dont understand first qestion but second question has a solution: ```d intrinsic_graph!T make_graph(T, Args...)(auto ref T val, auto ref Args args){ return new intrinsic_graph!T(val, args); } instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = make_graph(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = make_graph(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ``` Okay, to clarify just in case I'm very confusing because I'm up late. If I wanted a "multipleGraph". A graph that takes multiple values and plots them on the same graph. I need to store a buffer for each dataSource. Luckily, because I'm painting them to the screen, the buffers only really need to be float even if they started as a boolean, int, or double. However, if I'm keeping a list of pointers to things I want to snoop when I call onTick(), I can't think of a way to support multiple types: ```D class intrinsicGraph(T) { T* dataSource; float[] buffer; void onTick() { //grab datasource data and do something. buffer ~= to!float(*datasource); } } auto g = intrinsicGraph!float(); ``` But what if there's multiple types? ```D class multiGraph(???) { ???[] dataSources; float[] buffers; void onTick() { //grab datasource data and do something. foreach(d, i; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto g = multiGraph!???(, , ); ``` This is a kinda "dynamic language" feature but it feels like this information is theoretically, knowable at static, compile-time. I know what the variable types will be at compile-time, but I don't know how to put them all in one class and reference them automatically. Try variadic templates: ```d import std.meta : staticMap, allSatisfy; import std.traits : PointerTarget, isPointer; import std.conv : to; alias Pointer(T) = T*; class MultiGraph(Ts...){ alias DataSources = staticMap!(Pointer, Ts); DataSources dataSources; float[][DataSources.length] buffers; this(DataSources dataSources){ this.dataSources = dataSources; } void onTick() { //grab datasource data and do something. foreach(enum i, ref d; dataSources) buffers[i] ~= to!float(*d); //or whatever } } auto multiGraph(Ts...)(Ts ts) if(allSatisfy!(isPointer, Ts)){ return new MultiGraph!(staticMap!(PointerTarget, Ts))(ts); } void main(){ float myFloat; double myDouble; int myInteger; auto g = multiGraph(, , ); } ```
Re: Template shenannigans with multiple datatypes
On Friday, 13 May 2022 at 06:43:39 UTC, Chris Katko wrote: I have an intrinsicGraph(T) class that is given a pointer to a T dataSource and automatically polls that variable every frame to add it to the graph, whether it's a float, double, integer, and maybe bool. [...] I dont understand first qestion but second question has a solution: ```d intrinsic_graph!T make_graph(T, Args...)(auto ref T val, auto ref Args args){ return new intrinsic_graph!T(val, args); } instrinsicGraph!float testGraph; instrinsicGraph!ulong testGraph2; // later testGraph = make_graph(units[0].x, 100, 300, COLOR(1,0,0,1)); testGraph2 = make_graph(g.stats.fps, 100, 500, COLOR(1,0,0,1)); ```
Re: Virtual methods on stack objects
On Wednesday, 11 May 2022 at 20:53:21 UTC, Marvin Hannott wrote: On Wednesday, 11 May 2022 at 20:23:07 UTC, Ali Çehreli wrote: On 5/11/22 13:06, Marvin Hannott wrote: > I appreciate the answer, don't much like the "solutions". Me neither. :) > It's not so much about copying Great! > scoped class objects should have value semantics. std.typecons.scoped does exactly that: https://dlang.org/phobos/std_typecons.html#scoped import std.stdio; import std.typecons; interface Animal { string sing(); } class Cat : Animal { this() { writeln("Hi!"); } ~this() { writeln("Bye!"); } string sing() { return "mew"; } } void foo(Animal animal) { writeln(animal.sing()); } void bar() { auto cat = scoped!Cat(); foo(cat); } void main() { bar(); } The output: Hi! mew Bye! Ali Yeah, but you can't return `Cat` . And the documentation for `scoped` says: It's illegal to move a class instance even if you are sure there are no pointers to it. As such, it is illegal to move a scoped object. That's kinda very limiting. Anyway, I cooked up another idea based on your first suggestions. ```D struct S { static private interface I { int f(int i); } static private final class A : I { int f(int i) {return i;} } static private final class B : I { int f(int i) {return i+ 1;} } private I i; private int d; this(int d) { this.d = d; if(d < 10) { i = scoped!A(); }else { i = scoped!B(); } } int f() { return i.f(d);} } ``` I mean, this is a super dumb example, but it kinda works. And I think it could be made a lot less tedious with some mixin magic. `scoped` is not necesary, try this: ```d import std.typecons; struct S{ static private interface I{ int f(int i)const; } static private final class A : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i;} } static private final class B : I{ static immutable typeof(this) instance = new immutable typeof(this)(); int f(int i)const {return i+ 1;} } private immutable I i; private int d; this(int d){ this.d = d; if(d < 10) i = A.instance; else i = B.instance; } int f() { return i.f(d);} } void main(){ import std.stdio; S(1).f().writeln(); /// 1 S(100).f().writeln(); /// 101 } ```
Re: dip1000 return scope dmd v 2.100
On Friday, 6 May 2022 at 17:17:01 UTC, Dennis wrote: On Friday, 6 May 2022 at 09:24:06 UTC, vit wrote: [...] They were recently updated to match the implementation in 2.100. [...] `return scope` means pointer members (such `this.ptr`, `C.ptr`) may not escape the function, unless they are returned. If you call `test()` on a `scope` variable, the return value will be a scope pointer. [...] Thanks
dip1000 return scope dmd v 2.100
Hello, new dmd (2.100) has return/scope changes. It look like examples at page https://dlang.org/spec/function.html#ref-return-scope-parameters are no longer relevant. What difference are between `return scope`, `scope return` and `return`? Why `void* ptr` in struct change effect of `scope return` ? ```d @safe: struct A{ int val; //void* ptr; int* test() scope return{ return// OK } } struct B{ int val; void* ptr; int* test() return{ return // OK } } struct C{ int val; void* ptr; int* test() scope return{ return // Error: returning `` escapes a reference to parameter `this` } } void main(){} ```
Re: How to unpack template parameters,Or how to forward parameters?
On Friday, 6 May 2022 at 00:41:18 UTC, zjh wrote: Hello everyone,I have following function: ```d import core.stdc.stdio; void f(int i,int j){ printf("%i,%i",i,j); } ``` I want to forward `int[N]` to `(int i,int j)` etc. How can I write a forwarding function? ```d void ff(alias g,int...I)(int[2]k){ g(k[I]); }//How to unpack template variable parameters? void f(int[2]k){ ff!(f,0,1)(k);//how to forward? } ``` main function: ```d extern(C):void main() { int[2] a=[2,4]; f(a);//calling like this } ``` Try this: ```d import core.stdc.stdio; void f(int i,int j){ printf("%i,%i",i,j); } import std.range : iota; import std.traits : isStaticArray; import std.meta : AliasSeq; template expand(alias arr) if(isStaticArray!(typeof(arr))){ auto get(size_t I)(){ return arr[I]; } alias Result = AliasSeq!(); static foreach(I; iota(0, arr.length)) Result = AliasSeq!(Result, get!I); alias expand = Result; } extern(C):void main(){ int[2] a=[2,4]; f(expand!a); } ```
Re: Why isn't my dynamic array method doesn't work for this type?
On Thursday, 5 May 2022 at 11:49:29 UTC, vit wrote: On Thursday, 5 May 2022 at 10:40:44 UTC, rempas wrote: I have created a structure that is a actually an array that allocates memory and growths. It is a template and it has worked with a couple of types that I have tried with. It doesn't work with one tho and I cannot understand why. I will list the smallest possible code I could. Keep in mind that it is a couple of code. For anyone that wants to read it, keep in mind that I have to make this code work with LDC and using "-betterC". [...] ```d this.capacity += DEF_VEC_REALLOC_SIZE; //realloc(this.ptr, T.sizeof * DEF_VEC_REALLOC_SIZE); this.ptr = realloc(this.ptr, T.sizeof * this.capacity); //<<-- ``` ```d void add(T element) { if (this.capacity == this.length) { this.capacity += DEF_VEC_REALLOC_SIZE; this.ptr = realloc(this.ptr, T.sizeof * this.capacity); if (!this.ptr) { // Re-allocation error check fprintf(stderr, "Error: Could not allocate more memory for the *%s object! Exiting...", cast(char*)(T).stringof); exit_prog(1); } } this.ptr[this.length++] = element; } ```
Re: Why isn't my dynamic array method doesn't work for this type?
On Thursday, 5 May 2022 at 10:40:44 UTC, rempas wrote: I have created a structure that is a actually an array that allocates memory and growths. It is a template and it has worked with a couple of types that I have tried with. It doesn't work with one tho and I cannot understand why. I will list the smallest possible code I could. Keep in mind that it is a couple of code. For anyone that wants to read it, keep in mind that I have to make this code work with LDC and using "-betterC". [...] ```d this.capacity += DEF_VEC_REALLOC_SIZE; //realloc(this.ptr, T.sizeof * DEF_VEC_REALLOC_SIZE); this.ptr = realloc(this.ptr, T.sizeof * this.capacity); //<<-- ```
Re: Help with DynamicArray of Emsi Containers
On Saturday, 30 April 2022 at 20:22:43 UTC, Christian Köstlin wrote: I am struggling with initializing an Emsi Containers DynamicArray in a nice way. Some background information of my usecase: I experimenting in porting some old 3d engine code of mine from c++ to dlang. In the engine I want to exactly control when resources are freed and not rely on the garbage collector. For that I am using reference counters courtesy of autoptr. e.g. ```d alias Texture = IntrusivePtr!TextureData; // dub package autoptr class TextureData { IFImage image; // dub package imagefmt } ``` another class of mine now is supposed to hold several of those textures for multitexturing and should be initialized in its constructor: ```d class Appearance { Texture[] textures; this(Texture[] textures) { this.textures = textures; } } ``` Unfortunately this does not work properly together with autoptr's (see https://github.com/submada/autoptr/issues/5#issuecomment-997683868). Because of that I am using now DynamicArrays from Emsi Containers, but I am having trouble initializing them: ```d class Apperance { DynamicArray!Texture textures; this(DynamicArray!Texture textures) { this.textures = textures; } } ``` does not compile. What would be the best way to initialize the variable? Kind regards, Christian DynamicArray has disabled postblit (is not copyable). Package autoptr is deprecated (internaly redirected to btl:atuoptr), all functionality is moved to package [BTL](https://code.dlang.org/packages/btl) (subpackage btl:autoptr). This library contains subpackage btl:vector with functionality like DynamicArray with support for copying. I use IntrusivePtr inside Vector/SmallVector and i have no problems.
Re: generic function instance without call
On Wednesday, 27 April 2022 at 16:03:32 UTC, user1234 wrote: On Wednesday, 27 April 2022 at 15:23:26 UTC, vit wrote: Hi, is it possible to get address of generic function instance for specified arguments without calling the function? Example: ```d auto foo(alias fn, Args...)(auto ref Args args){ ///return function/delegate type of `fn` for arguments `args` } void main(){ long x; auto fn = foo!((a, b) => true)(new int(42), x); static assert(is(typeof(fn) == bool function(int*, scope ref long)@safe pure nothrow @nogc )); } ``` yeah sure; declare an alias that (fully) specialize the generic func and take the address using the alias Identifier. This work for types but not for attributes like `scope`, `return` and `auto ref`.
Re: generic function instance without call
Fix: ```d auto fn = foo!((a, ref b) => true)(new int(42), x); ```
generic function instance without call
Hi, is it possible to get address of generic function instance for specified arguments without calling the function? Example: ```d auto foo(alias fn, Args...)(auto ref Args args){ ///return function/delegate type of `fn` for arguments `args` } void main(){ long x; auto fn = foo!((a, b) => true)(new int(42), x); static assert(is(typeof(fn) == bool function(int*, scope ref long)@safe pure nothrow @nogc )); } ```
Re: Reference counting example
On Tuesday, 26 April 2022 at 23:33:28 UTC, cc wrote: 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. Yor code has antoher big problem. Class Animal has @safe/pure/nothrow/@nogc destruction but class Cow has @system destructor. When you assign RC!Cow to RC!Animal you can have @safe @nogc ... function call @system destructor of Cow. I have library with check this kind of error for you (https://code.dlang.org/packages/btl). If you need aliasing (your case) or weak pointers then try it. ```d import std.stdio; import core.memory; import core.lifetime; import btl.autoptr; import btl.vector; alias ARRAY = Vector; alias RC = RcPtr; class Animal { void speak() { writeln("Animal: ???"); } ~this()@system{} //without this code doesnt compile } 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); } } 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.get.speak; } } void main() { auto used = GC.stats.usedSize; scope(exit) assert(GC.stats.usedSize == used); // GC is not touched! { assert(RC!Cow.make().get.x == 0); assert(RC!Cow.make(99).get.x == 99); } RC!Animal other; auto farm = RC!Farm.make(1); { auto cow = RC!Cow.make(1); farm.get.animals ~= cow; farm.get.animals ~= RC!Cow.make(2); other = farm.get.animals[1]; auto cowGoesOutOfScope = RC!Cow.make(70); } writeln("out, should have seen Cow#70's dtor"); farm.get.animals[0] = farm.get.animals[1]; writeln("animals[0] (Cow#1) just got overwritten so we should have seen its dtor"); farm.get.animals ~= RC!Cow.make(3); farm.get.pet(other); other = null; farm = null; writeln("done"); } ```
Re: Create an associative array with function pointers as the value
On Wednesday, 20 April 2022 at 10:42:59 UTC, rempas wrote: I'm trying to create an associative array where the keys will be a "string" type and the values will be function pointers. I'm using a custom type is called "file_struct" and for anyone that wants to try specifically with this type, the definition is the following: [...] You need shared static this for initializing immutable AA: ```d immutable void function(ref file_struct)[string] common_identifiers; shared static this(){ common_identifiers = [ "let" : _let, // "macro" : _macro, ]; } ```
scope variable `b` assigned to `a` with longer lifetime (-dip1000)
Hello, Why doesn't this code compile? ```d static struct Foo{ void *ptr; void proxySwap1(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{ auto tmp = this.ptr; this.ptr = rhs.ptr; rhs.ptr = tmp; } void proxySwap2()(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{ this.proxySwap1(rhs); } void proxySwap3()(scope ref typeof(this) rhs)scope pure nothrow @trusted @nogc{ auto tmp = this.ptr; this.ptr = rhs.ptr; rhs.ptr = tmp; } } void main()@safe{ scope Foo a; scope Foo b; a.proxySwap1(b);//OK a.proxySwap2(b);//OK a.proxySwap3(b); //Error: scope variable `b` assigned to `a` with longer lifetime } ```
Re: Can std.variant be used with std.container.rbtree?
On Saturday, 2 April 2022 at 14:49:15 UTC, Vijay Nayar wrote: On Saturday, 2 April 2022 at 14:35:10 UTC, Vijay Nayar wrote: The `tryMatch` method fails to compile, and instead I get the following error: ```d /dlang/dmd/linux/bin64/../../src/phobos/std/sumtype.d(2004): Error: static assert: "`handlers[0]` of type `int function(ref ubyte[] _1, ref ubyte[] _2) pure nothrow @nogc @safe` never matches" ``` Through sheer trial and error, I discovered that changing the handler arguments from `ref ubyte[]` to `const ref ubyte[]` the error goes away. However, I did not find any information in the documentation or code that made this requirement clear. It was basically a guess based on the fact that `string` has no trouble but `ubyte[]` did, and string is basically just `immutable(char[])`. So far, I'm finding that learning to use `SumType` is significantly more cryptic than `Variant`, by a large margin. I'll still give it a shot of course, because I want to get past this problem. Try this: ```d import std.sumtype; import std.algorithm : cmp; alias VarType = SumType!(double, ubyte[]); int opCmp(const ref VarType v1, const ref VarType v2) { //you need all combinations of types: static int impl(A, B)(auto ref A a, auto ref B b){ // (double, ubyte[]) or (ubyte[], double): static if(!is(immutable A == immutable B)) assert(0, "type missmatch"); // (ubyte[], ubyte[]): else static if(is(immutable A == immutable ubyte[])) return cmp(a, b); // (double, double): else return (a < b) ? (-1) : (a < b ? 1 : 0); } return tryMatch!impl(v1, v2); } void main(){ VarType b1 = cast(ubyte[]) [0x01, 0x02, 0x03]; VarType b2 = cast(ubyte[]) [0x01, 0x02, 0x04]; assert(opCmp(b1, b2) == -1); //operator overloading work only if opCmp is method. } ```
Re: Can std.variant be used with std.container.rbtree?
On Friday, 1 April 2022 at 22:22:21 UTC, Vijay Nayar wrote: Consider the following program: ```d void main() { import std.stdio; import std.container.rbtree; import std.variant; [...] Variant can contain any type => variant cannot assume attributes like pure nothrow @safe @nogc on its methods. RedBlackTree has nothrow dtor => Element type must have nothrow dtor => Variand need nothrow dtor... Similar for other methods. Try use ```std.sumtype```.
Re: How to create delegates with an independent scope?
On Wednesday, 30 March 2022 at 12:56:39 UTC, Vijay Nayar wrote: On Wednesday, 30 March 2022 at 12:53:10 UTC, vit wrote: use two delegates :) ```d (){ // Deliberately create a copy to keep in delegate scope. string myStr = i.dup; // The delegate will hopefully carry this copy around in its own scope. funcs ~= (() => myStr ~ " sandwich"); }(); ``` Very interesting. Both this and creating a "function creator function" work, and it seems clear that functions create their own scopes. However, it seems that loops do not, is that correct? Maybe I was thrown off by the surrounding `{ }`, but I had assumed that loops created their own scopes. It is bug: https://issues.dlang.org/show_bug.cgi?id=21929
Re: How to create delegates with an independent scope?
On Wednesday, 30 March 2022 at 12:46:07 UTC, Vijay Nayar wrote: Consider the following code example: ```d import std.stdio; void main() { alias DelegateT = string delegate(); // An array of delegates, each has their own scope. DelegateT[] funcs; foreach (i; ["ham", "cheese"]) { // Deliberately create a copy to keep in delegate scope. string myStr = i.dup; // The delegate will hopefully carry this copy around in its own scope. funcs ~= (() => myStr ~ " sandwich"); } foreach (f; funcs) { writeln(f()); } } ``` The expected output is: "ham sandwich" and then "cheese sandwich". The actual output is: "cheese sandwich" and then "cheese sandwich". It seems that the variable `myStr` is in a sort of shared scope for both functions in the array, and the last value written to it dominates. How do I create a delegate that acts like a [closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures), that is, it carries with it the environment in which it was created? use two delegates :) ```d import std; void main(){ alias DelegateT = string delegate(); // An array of delegates, each has their own scope. DelegateT[] funcs; foreach (i; ["ham", "cheese"]) { (){ // Deliberately create a copy to keep in delegate scope. string myStr = i.dup; // The delegate will hopefully carry this copy around in its own scope. funcs ~= (() => myStr ~ " sandwich"); }(); } foreach (f; funcs) { writeln(f()); } } ```
Re: How to make a generic function to take a class or struct by reference?
On Sunday, 27 March 2022 at 16:27:44 UTC, JN wrote: I would like to have only one definition of getX if possible, because they both are doing the same thing. I can't remove the ref one, because without a ref it will pass the struct as a temporary and compiler won't like that. ```d import std.stdio; struct Foo { int x; void doStuff() { *getX(this) = 5; } } class Bar { int x; void doStuff() { *getX(this) = 5; } } int* getX(T)(ref T t) { return } int* getX(T)(T t) { return } void main() { Foo foo; Bar bar = new Bar(); foo.doStuff(); bar.doStuff(); assert(foo.x == 5); assert(bar.x == 5); } ``` Try this: ```d int* getX(T)(return auto ref T t){ static if(is(T == class)) return else static if(is(T == struct) && __traits(isRef, t)) return else static assert(0, "no impl " ~ T.stringof); } ``` or: ```d int* getX(T)(return auto ref T t) if(is(T == class) || (is(T == struct) && __traits(isRef, t))){ return } ```
error forward references if scope
Hello, why this code compile without problems: ```d struct Query{ public const SharedPtr!Builder builder; } interface Builder{ void build(ref Query query); } struct SharedPtr(T){ enum touch_T = __traits(hasMember, T, "touch"); //... } void main(){ } ``` but if `ref Query query` is scope then there is error? ```d struct Query{ public const SharedPtr!Builder builder; } interface Builder{ void build(scope ref Query query); //SCOPE } struct SharedPtr(T){ enum touch_T = __traits(hasMember, T, "touch"); //... } void main(){ } ``` ``` src/app.d(3,1): Error: no size because of forward references src/app.d(4,18): Error: template instance `app.SharedPtr!(Builder)` error instantiating ```
Re: Cannot Call Super-Class Overloaded Function If Class has Function Override?
On Tuesday, 1 March 2022 at 08:40:12 UTC, Vijay Nayar wrote: I've randomly encountered a strange error, and I cannot find any explanation for it in the official documentation of syntax. [...] Here is more info (3.): https://docarchives.dlang.io/v2.078.0/spec/function.html#function-inheritance
Re: Cannot Call Super-Class Overloaded Function If Class has Function Override?
On Tuesday, 1 March 2022 at 08:40:12 UTC, Vijay Nayar wrote: I've randomly encountered a strange error, and I cannot find any explanation for it in the official documentation of syntax. Essentially, a class cannot call function overload in a super-class if the class itself contains an override. Is this a bug? Is this on purpose? Take a look at `B.otherThing()` below. ``` d void main() { abstract class A { // An abstract method for sub-classes abstract void doThing(string a, size_t b); // A convenience helper. void doThing(string a) { doThing(a, a.length); } } class B : A { // If this overload exists, something strange happens... override void doThing(string a, size_t b) { } void otherThing() { // Error: `B.doThing(string a, ulong b)` // is not callable using argument // types `(string)` doThing("hello"); super.doThing("hello"); // OK } } } ``` ```d void main() { abstract class A { // An abstract method for sub-classes abstract void doThing(string a, size_t b); // A convenience helper. void doThing(string a) { doThing(a, a.length); } } class B : A { // If this overload exists, something strange happens... override void doThing(string a, size_t b) { } alias doThing = typeof(super).doThing; //add super.doThing to overload set. void otherThing() { // Error: `B.doThing(string a, ulong b)` // is not callable using argument // types `(string)` doThing("hello"); super.doThing("hello"); // OK } } } ```
Re: opCast in class prevents destroy
On Tuesday, 1 March 2022 at 08:16:13 UTC, Mike Parker wrote: On Tuesday, 1 March 2022 at 07:16:11 UTC, bauss wrote: Right now if you want to add an additional cast then you have to implement ALL the default behaviors and then add your custom cast. It's two template functions like the OP used: one for T to catch everything, and one specialization. That doesn't seem correct to me at least. Depends on your perspective I guess. For the inverse, when you want to allow only one kind of cast and prevent everything else, you only have to implement one template right now. If that were not the case, then you'd have to implement an additional catch-all template that bombs out with a static assert. So either way makes sense, IMO. Though I totally understand how the current behavior can be a surprise when people expect it to behave like, e.g., C++. But D is not C++. So is `opCast` intended to expand the list of target types (like C++), or is it intended to define it? The spec says, "To define how one type can be cast to another", which doesn't really answer the question. Now is possible this: ```d import std.stdio; struct Foo{ int i; this(int i)@safe{ this.i = i; writeln("ctor(", i, "): ", cast(void*)); } Foo opCast(T, this This)()@safe if(is(immutable T == immutable This)){ return Foo(2); } ~this()@safe{ writeln("dtor(", i, "): ", cast(void*)); } } struct Bar{ const Foo foo; this(int i)@safe{ this.foo = Foo(i); } } void main()@safe{ Bar bar = Bar(1); } ``` Result: ```d ctor(1): 7FFE0D5A94A8 //dtor for Foo(1) is never called. ctor(2): 7FFE0D5A9410 dtor(2): 7FFE0D5A9470 dtor(2): 7FFE0D5A9470 //dtor for Foo(2) is called twice. ```
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote: so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // -- `r` is not input range, try this: ```d module test; import std; string RandomChoice1(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } string RandomChoice2(R...)(R r)@nogc { auto rnd = MinstdRand0(unpredictableSeed); switch(rnd.front % R.length){ static foreach(enum I, alias arg; r){ case I: return arg; } default: assert(0, "no impl"); } } void main() { writeln( RandomChoice1("typeA", "typeB", "typeC") ); writeln( RandomChoice2("typeA", "typeB", "typeC") ); } ```
Re: forward tuple arg to local variable + dtor
On Saturday, 22 January 2022 at 19:01:09 UTC, Stanislav Blinov wrote: On Saturday, 22 January 2022 at 18:00:58 UTC, vit wrote: [...] Take by value and make a copy without forwarding: ```d import std.typecons : Tuple; import std.meta : allSatisfy; [...] Thanks, second options is what I need. (In my case forwarding is more complex because weak ptrs need lock()).
Re: forward tuple arg to local variable + dtor
On Saturday, 22 January 2022 at 17:23:12 UTC, Ali Çehreli wrote: On 1/22/22 07:17, vit wrote: > Why local variable of type tuple call destructors immediately after > initialization? I don't even understand where the local variable comes from. If you want a pair of Foo objects, I would use std.typeconst.Tuple. Otherwise I would use AliasSeq as I understand it like the following: alias tup = AliasSeq!(Foo, Foo); static foreach(Type; tup) {{ Type x; writeln("check(", x.i, "): ", cast(void*)); }} So, to me, AliasSeq!(Foo, Foo) is just a pair of types. I instantiate an object for each type individually and use it inside. Ali I want implement something like this: ```d import std.stdio : writeln; import std.meta : AliasSeq, staticMap; import core.memory : pureMalloc, pureFree; import core.lifetime : emplace, forward; void main()@safe{ auto rc1 = RcPtr!int.make(1); //ref counted pointer long result = 0; //apply can be @safe apply!((ref int a, ref long b){ rc1 = null; //apply has copy of rc1, a is not dangling reference result = a + b; })(rc1, RcPtr!long.make(2)); assert(result == 3); } //@safe access to data of multiple ref counted objects: public auto apply(alias fn, Args...)(scope auto ref Args args){ Args params = forward!args; //copy lvalue and move rvalue args @property auto ref elm(alias param)()@trusted{ return param.get(); } return fn(staticMap!(elm, params)); } //simple implementation of ref counted pointer struct RcPtr(T){ private Payload* payload; private this(Payload* payload)@safe{ this.payload = payload; } //copy ctor public this(ref typeof(this) rhs){ this.payload = rhs.payload; if(payload) payload.count += 1; } //make data public static auto make(Args...)(auto ref Args args){ Payload* payload = ()@trusted{ return cast(Payload*)pureMalloc(Payload.sizeof); }(); emplace(payload, forward!args); return RcPtr(payload); } public ~this(){ this.opAssign(null); } //release payload void opAssign(typeof(null) nil){ if(payload){ payload.count -= 1; if(payload.count == 0){ destroy(*payload); ()@trusted{ pureFree(payload); }(); payload = null; } } } // ref T get()@system{ assert(payload); return payload.data; } private struct Payload{ int count = 1; T data; this(Args...)(auto ref Args args){ data = T(forward!args); } } } ```
Re: forward tuple arg to local variable + dtor
On Saturday, 22 January 2022 at 14:23:32 UTC, Adam Ruppe wrote: You can't forward to a local variable. Local variables will be a copy of the tuple. forward only actually works if sent *directly* to another function call. There's a bunch of things in D that only work in function parameter lists and not local variables. This is one of them. Thanks, Why local variable of type tuple call destructors immediately after initialization? ```d import std.stdio : writeln; import std.meta : AliasSeq; struct Foo{ int i; this(int i){ this.i = i; writeln("ctor(", i, "): ", cast(void*)); } ~this(){ writeln("dtor(", i, "): ", cast(void*)); i *= -1; } } void main(){ { AliasSeq!(Foo, Foo) tup; static foreach(alias x; tup) writeln("check(", x.i, "): ", cast(void*)); //x is destructed } } ``` Print: ``` dtor(0): 7FFF30D76868 dtor(0): 7FFF30D76858 check(0): 7FFF30D76858 //dangling? check(0): 7FFF30D76868 //dangling? ```
forward tuple arg to local variable + dtor
Hello, Why is tuple variable `params` immediately destructed after its construction? Why is `check(-2)` after `dtor(2)`? Code: ```d import std.stdio : writeln; import core.lifetime : forward, move; struct Foo{ int i; this(int i){ this.i = i; writeln("ctor(", i, "): ", cast(void*)); } ~this(){ writeln("dtor(", i, "): ", cast(void*)); i *= -1; } } void seq(Args...)(auto ref Args args){ Args params = forward!args; writeln("params initialized"); alias foo = params[0]; writeln("check(", foo.i, "): ", cast(void*)); } void main(){ writeln("Foo(1):"); { auto foo = Foo(1); writeln("check(", foo.i, "): ", cast(void*)); } writeln("\nFoo(2):"); seq(Foo(2)); } ``` Output: ``` Foo(1): ctor(1): 7FFEBCAF0538 check(1): 7FFEBCAF0538 dtor(1): 7FFEBCAF0538 Foo(2): ctor(2): 7FFEBCAF0548 dtor(2): 7FFEBCAF04F0 params initialized check(-2): 7FFEBCAF04F0 dtor(0): 7FFEBCAF0558 ```
Re: Function prototype overloading does not work ?
On Wednesday, 19 January 2022 at 08:47:27 UTC, Enjoys Math wrote: ``` module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const { static if (op == "+") { Expr right = null; if (s == ".." || s == "..." || s == "") { right = new Dots(); } if (right !is null) return new Op("+", [this, right]); } } override string toString() const { assert(0); } Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } Expr sub(Expr x, ref Var y) { return sub(x, new VarExpr(y)); } Expr sub(ref Var x, Expr y) { return sub(new VarExpr(x), y); } Expr sub(int x, Expr y) { return sub(ZZ(x), y); } Expr sub(Expr x, int y) { return sub(x, ZZ(y)); } Expr sub(ref Var x, ref Var y) { return sub(new VarExpr(x), new VarExpr(y)); } Expr sub(ref Var x, int y) { return sub(new VarExpr(x), ZZ(y)); } Expr sub(int x, ref Var y) { return sub(ZZ(x), new VarExpr(y)); } override bool opEquals(Object o) { return this is o; } } ``` See all the overloads I had to make to sub in order to bypass identity assignment for classes. I.e. Var can't be of type Expr. Anyway, this approach is not working because code calling `Expr.sub(int, Var)` is not seeing the definitions. It says no function matching those args, but clearly there are! Try replacing methods sub with template: ```d module expr; import dots; import operator; import equation; import var; import var_expr; import zz_const; class Expr { public: void opBinary(string op)(string s) const; override string toString() const; Expr sub(Expr x, Expr y) { if (this == x) return y; return this; } //template sub: Expr sub(T, U)(auto ref T x, auto ref U y){ //transform parameter to Expr: static Expr expr(E)(auto ref E e){ static if(is(E : Expr)) return e; else static if(is(E : int)) return ZZ(e); else static if(is(E : Var)) return new VarExpr(e); else static assert(0, "no impl " ~ E.stringof); } //call sub(Expr, Expr) this.sub(expr(x), expr(y)); } override bool opEquals(Object o) ; } ```
Re: alias and __VERSION__ condition doesn't play well
On Wednesday, 19 January 2022 at 04:15:54 UTC, Steven Schveighoffer wrote: On 1/18/22 7:19 AM, vit wrote: On Tuesday, 18 January 2022 at 12:05:38 UTC, Paul Backus wrote: On Tuesday, 18 January 2022 at 04:42:45 UTC, frame wrote: At the very top of my module I have this declaration: ```d static if (__VERSION__ >= 2098) { alias Foo = TypeA; } else { alias Foo = TypeB; } ``` No problem inside the module itself but this doesn't work when imported from another module: Error: undefined identifier `Foo` Works for me: https://run.dlang.io/is/XZlvQ8 It works until you have cyclic dependencies: https://run.dlang.io/is/wDDcK5 Has nothing to do with `__VERSION__`: https://run.dlang.io/is/pa8lDy That does seem like a bug. And it's LDC specific, dmd seems to work fine. -Steve In dmd is order of module compilation different. Same problem: https://run.dlang.io/is/NkySAw This is not only problem with imports: ```d class Foo{ Bar.B b; static if(true) alias F = int; } class Bar{ Foo.F f; //Error: no property `F` for type `onlineapp.Foo` static if(true) alias B = int; } void main(){} ```
Re: alias and __VERSION__ condition doesn't play well
On Tuesday, 18 January 2022 at 12:05:38 UTC, Paul Backus wrote: On Tuesday, 18 January 2022 at 04:42:45 UTC, frame wrote: At the very top of my module I have this declaration: ```d static if (__VERSION__ >= 2098) { alias Foo = TypeA; } else { alias Foo = TypeB; } ``` No problem inside the module itself but this doesn't work when imported from another module: Error: undefined identifier `Foo` Works for me: https://run.dlang.io/is/XZlvQ8 It works until you have cyclic dependencies: https://run.dlang.io/is/wDDcK5
Re: alias and __VERSION__ condition doesn't play well
On Tuesday, 18 January 2022 at 04:42:45 UTC, frame wrote: At the very top of my module I have this declaration: ```d static if (__VERSION__ >= 2098) { alias Foo = TypeA; } else { alias Foo = TypeB; } ``` No problem inside the module itself but this doesn't work when imported from another module: Error: undefined identifier `Foo` While this workaround works: ```d template getAlias() { static if (__VERSION__ >= 2098) { alias getAlias = TypeA; } else { alias getAlias = TypeB; } } alias Foo = getAlias!(); ``` Is there a reason for that? static ifs and mixins need semantic analysis to expand, but when you import module, the semantic analysis doesn't run yet (depends on order). Beter workaround is: ```d import std.traits : Select; alias Foo = Select!(__VERSION__ >= 2098, TypeA, TypeB); ```
Re: error: rvalue constructor and a copy constructor
On Wednesday, 12 January 2022 at 08:04:19 UTC, vit wrote: Hello, I have this code: ```d [...] run.dlang.io has old version of dmd-beta/dmd-nightly with bug
error: rvalue constructor and a copy constructor
Hello, I have this code: ```d import core.lifetime : move, forward; import std.stdio : writeln; struct Foo{ int i; static auto make(int i){ Foo tmp; tmp.i = i; return move(tmp); } this(scope const ref typeof(this) rhs){ this.i = rhs.i; writeln("copy"); } this(T)(scope const T rhs) if(is(immutable T == immutable typeof(this))){ this.i = rhs.i; writeln("move"); } } auto foo(T)(auto ref T x){ return Foo(forward!x); } void main(){ Foo x = foo(Foo.make(1)); writeln("end"); } ``` When is this code compiled with 2.098.1 then it print: ``` Error: Cannot define both an rvalue constructor and a copy constructor for `struct Foo` Template instance `__ctor!(Foo)` creates a rvalue constructor for `struct Foo` Error: template instance `onlineapp.Foo.__ctor!(Foo)` error instantiating instantiated from here: `foo!(Foo)` ``` When is compiled by dmd-beta/dmd-nightly then it works fine. Is dmd-beta/dmd-nightly with bug or is this new valid behaviour?
Re: A slice consisting of non-consecutive elements of an array?
On Wednesday, 12 January 2022 at 06:58:47 UTC, vit wrote: On Wednesday, 12 January 2022 at 06:43:40 UTC, forkit wrote: On Wednesday, 12 January 2022 at 06:16:49 UTC, vit wrote: Yes std.algorithm : filter. ```d import std.stdio : writeln; import std.algorithm : filter; void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; writeln(a); writeln(a.filter!(x => x == "one")); } ``` Interesting. I looked it up.. it says "returns a new range..." Does that mean what I think it means (i.e. a new allocation takes place) ? No, it is only view to old slice: ```d void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; auto b = (()@nogc => a.filter!(x => x == "one"))(); writeln(a); writeln(b); } ``` filter is implemented like this (but more generic): ```d import std.stdio : writeln; auto filter(alias fn, T)(T[] slice){ //InputRange: static struct Filter{ T[] slice; bool empty()const{return slice.length == 0;} T front(){return slice[0];} void popFront(){ do{ slice = slice[1 .. $]; }while(slice.length && !fn(slice[0])); } } return Filter(slice); } void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; writeln(a); writeln(a.filter!(x => x == "one")); } ```
Re: A slice consisting of non-consecutive elements of an array?
On Wednesday, 12 January 2022 at 06:43:40 UTC, forkit wrote: On Wednesday, 12 January 2022 at 06:16:49 UTC, vit wrote: Yes std.algorithm : filter. ```d import std.stdio : writeln; import std.algorithm : filter; void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; writeln(a); writeln(a.filter!(x => x == "one")); } ``` Interesting. I looked it up.. it says "returns a new range..." Does that mean what I think it means (i.e. a new allocation takes place) ? No, it is only view to old slice: ```d void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; auto b = (()@nogc => a.filter!(x => x == "one"))(); writeln(a); writeln(b); } ```
Re: A slice consisting of non-consecutive elements of an array?
On Wednesday, 12 January 2022 at 05:27:08 UTC, forkit wrote: I am familiar with the concept of a slice in D. However, a slice is a consecutive slice, is in not? (e.g) [4..$-1] I would like a slice (or a view, or whatever name you wanna call it), of particular elements within an array that may not be consecutive. e.g. [4-7,8,10,13-16] Consider below: I want a slice/view on this array that only contains elements with the string "one". ["one", "one", "two", "one", "two", "one", "one", "two] Most importantly, I do NOT want to allocate - so the slice/view needs to be 'referencing' existing data (not copying it). Yes, I can hard code it, C style. I already know this. Does phobos offer something like this? Yes std.algorithm : filter. ```d import std.stdio : writeln; import std.algorithm : filter; void main()@safe{ auto a = ["one", "one", "two", "one", "two", "one", "one", "two"]; writeln(a); writeln(a.filter!(x => x == "one")); } ```
Re: fixedstring: a @safe, @nogc string type
On Tuesday, 11 January 2022 at 11:16:13 UTC, Moth wrote: On Tuesday, 11 January 2022 at 03:20:22 UTC, Salih Dincer wrote: [snip] glad to hear you're finding it useful! =] ... i know there's currently some wierdness with wchars / dchars equality that needs to be fixed [shouldn't be too much trouble... If you try mixing char/wchar/dchar, you need encoding/decoding for utf-8, utf-16 and utf-32 ( maybe even LE/BE ). It become complicated very fast...
Re: Added copy constructors to "Programming in D"
On Saturday, 8 January 2022 at 16:24:03 UTC, Ali Çehreli wrote: On 1/8/22 5:49 AM, Stanislav Blinov wrote: >> Of course, now I stress that postblit is discouraged. > > Bit early, methinks. Copy ctors aren't even fully supported by the > runtime yet. Thanks. The spec discourages postblit as well. What's the best of saying it then? Something like "There are still limitations of copy constructors as of this writing." Or there are just bugs? Ali Bugs, for example: When appending to dynamic array reallocate memory, then copy ctors are ignored. Assignment of static arrays doesn't call copy constructor for elements. dup/idup doesn't call copy constructors... This is necessary to fix it: [SAoC 2021] Replace druntime Hooks with Templates https://forum.dlang.org/thread/flwjoxilxfpvdjhee...@forum.dlang.org
Re: mixin does not work as expected
On Wednesday, 5 January 2022 at 09:17:54 UTC, rempas wrote: On Wednesday, 5 January 2022 at 09:02:53 UTC, vit wrote: Try this: ```d pragma(msg, type_check!("static if", "i8", "true", "5", "4", "10", "5")); ``` Result: ```d static if(is_same!(num, i8)) { mixin(base_digit!("5", "4", "10", "5")); static if (true) { mixin(overflow_check!"i8.min"); } } ``` is_same - is undefined i8 - is undefined overflow_check!"i8.min" - ? This code with mixins is horrible :) Hi and thanks for your time. "pragma(msg, ...)" will indeed work but it will print the code in the standard output. Is there something that I'm missing? 1) That printed code on standard output is wrong, missing declaration for is_same and i8. 2) if-else must be in same mixin: ```d mixin("" + type_check!("static if", "i8", "true", "5", "4", "10", "5") + type_check!("else static if", "i16", "true", "7", "6", "18", "8") + type_check!("else static if", "i32", "true", "12", "10", "34", "13") + type_check!("else", "i64", "true", "21", "18", "66", "24") ); ``` 3) last type_checkin signed and unsigned part of function test has else with condition. ```d else(is_same!(num, i64)) { mixin(base_digit!("21", "18", "66", "24")); static if (true) { mixin(overflow_check!"i64.min"); } } ```
Re: mixin does not work as expected
On Wednesday, 5 January 2022 at 08:40:15 UTC, rempas wrote: I'm trying to use mixins and enums to "expand" code in place but the results are not what I expected and I'm getting an weird error. I have created the smallest possible example to reproduce the error and it is the following: [...] And you cannot have else statement in different mixin: ```d extern (C) void main() { ///OK: mixin("static if(true){}else{}"); ///ERROR: mixin("static if(true){}"); mixin("else{}"); } ```
Re: mixin does not work as expected
On Wednesday, 5 January 2022 at 08:40:15 UTC, rempas wrote: I'm trying to use mixins and enums to "expand" code in place but the results are not what I expected and I'm getting an weird error. I have created the smallest possible example to reproduce the error and it is the following: [...] Try this: ```d pragma(msg, type_check!("static if", "i8", "true", "5", "4", "10", "5")); ``` Result: ```d static if(is_same!(num, i8)) { mixin(base_digit!("5", "4", "10", "5")); static if (true) { mixin(overflow_check!"i8.min"); } } ``` is_same - is undefined i8 - is undefined overflow_check!"i8.min" - ? This code with mixins is horrible :)
Re: opCast + dtor error
On Wednesday, 29 December 2021 at 01:00:53 UTC, Tejas wrote: On Tuesday, 28 December 2021 at 18:27:36 UTC, vit wrote: [...] Since a destructor ignores `const`, I think adding the `~this` to Foo manually is somehow making the compiler have to actually cast away const, which it is doing via `cast(Foo) foo`, which fails since you've declared your own `opCast` that only accepts arguments implicitly convertible to `bool`. I say this because removing the specialisation in `opCast` and changing the return type of it to `Foo` works : ```d struct Foo{ Foo opCast(T)()const { assert(0); return this; } ~this() {} } struct Bar{ const Foo foo; } void main(){ //Bar bar = Bar(); //this will trigger the assertion failure } ``` Thanks, you are right, generated Bar.~this() try use opCast to cast const away. Is look like bug in compiler. I stop using opCast for now.
opCast + dtor error
Hi, why this code doesn't compile? ```d struct Foo{ bool opCast(T : bool)()const{ assert(0); } ~this(){} } struct Bar{ const Foo foo; } void main(){ } ``` Error: template instance `opCast!(Foo)` does not match template declaration `opCast(T : bool)()`
Re: How to properly use variadic templates (functions)?
On Tuesday, 21 December 2021 at 08:26:17 UTC, rempas wrote: On Tuesday, 21 December 2021 at 08:11:39 UTC, Anonymouse wrote: I'm not certain I understand, but won't `foreach (i, a; args) { /* ... */ }` in his example do that? As in, if you necessarily must index `args` instead of using a foreach variable, ```d import core.stdc.stdio : putc, stdout; void print(T...)(string prompt, T args) { foreach (i, a; args) { alias A = typeof(args[i]); static if (is(A : string)) { for (int j = 0; j < args[i].length; j++) { putc(args[i][j], stdout); } } else { // handle your other types print("", A.stringof); } } } void main() { print("Prompt (ignored)", "Hello", " world!\n", 123); } ``` No it will not. I will try to explain it the best way I can. When I say I want to index args, I mean that I want to index and choose which argument to use rather than use them continuously one after another inside a `foreach`. For example check the following call: `print("Hello %s!%c", "world", '\n');` In that case I want to first print print from "H" up to (but not include) "%s". Then I want to print the first argument. After that, I want to print the '!' character and then I want to print the second argument. So I need a way to keep track which argument was the last one I printed and manually choose which argument to use. So `foreach` will not do in that case because I don't want to continuously use the arguments one after another. Is is more clear now? "writef" exists in phobos so I'm pretty sure that there is a way to do that. You can use switch + static foreach: ```d import std.stdio; //this print args in reverse order: void print(T...)(string prompt, T args) { void print_arg(size_t index){ switch(index){ static foreach(i, a; args){ case i: // handle your other types write(a); return; } default: assert(0, "no impl"); } } write(prompt); size_t len = args.length; while(len --> 0) print_arg(len); } void main(){ print("Prompt (ignored): ", "Hello", " world!\n", 123); } ```
Re: dynamic array + copy ctor
On Sunday, 19 December 2021 at 23:21:00 UTC, Stanislav Blinov wrote: On Sunday, 19 December 2021 at 22:29:21 UTC, vit wrote: Hello, Why is copy ctor in this example not called? Because D runtime isn't properly married to copy constructors yet. I.e. it's a bug, a variant of this one: https://issues.dlang.org/show_bug.cgi?id=20879 Thanks, That bug is 1.5 years old. Are this problems with copy ctors hard to fix? Are copy ctors still experimental functionality?
dynamic array + copy ctor
Hello, Why is copy ctor in this example not called? ```d import std.stdio; struct Foo { int i; this(int i){ this.i = i; writeln("init: ", i); } this(ref typeof(this) rhs){ this.i = rhs.i; writeln("copy: ", i); } ~this() { writeln("~dtor:", i); } } void main(){ Foo[] foos; foos ~= Foo(1); while(foos.capacity > foos.length) foos ~= Foo(0); foos ~= Foo(2); import core.memory; GC.collect(); } ``` result: ``` init: 1 init: 2 ~dtor:1 ~dtor:2 ~dtor:1 ``` First Foo is destructed 2x.
Re: template ctor overload Segmentation fault
On Tuesday, 14 December 2021 at 14:40:00 UTC, RazvanN wrote: On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped) PR: https://github.com/dlang/dmd/pull/13427 Thanks, I got it to work for now: ```d struct Foo(T){ this(Rhs, this This)(auto ref scope Rhs rhs) if(__traits(isRef, rhs) == false){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ```
Re: template ctor overload Segmentation fault
On Sunday, 12 December 2021 at 18:32:28 UTC, Imperatorn wrote: On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped) What are you trying to accomplish? Something like this: ```d import std.traits : CopyConstness; struct UniquePtr(T){ alias Type = T; this(Rhs, this This)(scope Rhs rhs) if(is(CopyConstness!(Rhs, Rhs.Type*) : CopyConstness!(This, This.Type*))){ //... } //one of copy ctors: this(ref scope typeof(this) rhs){ //... } static UniquePtr make(Args...)(Args args){ return UniquePtr.init; } } void main(){ const UniquePtr!(int) cui = UniquePtr!(const int).make(1); const UniquePtr!(const int) cuci = UniquePtr!(const int).make(1); UniquePtr!(const int) uci = UniquePtr!(int).make(1); UniquePtr!(int) ui = UniquePtr!(int).make(1); const UniquePtr!(int) xcui = UniquePtr!(immutable int).make(1); const UniquePtr!(const int) xcuci = UniquePtr!(immutable int).make(1); } ``` This work but UniquePtr canno't be inside struct because Segmentation fault.
template ctor overload Segmentation fault
Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped)
autoptr (ref counted pointers)
Hello, I implemented reference counted pointers supporting: - weak pointers (optional). - aliasing. - atomic/non-atomic counters. - multithread ref counted pointers . - arrays. - destructors with attributes - pure, const, immutable and shared support. - limited dip1000 and @safe support. - intrusive pointers - unique pointers Api is inspired with std::shared_ptr Implementation is inspired by clang std::shared_ptr. git: https://github.com/submada/autoptr doc: https://submada.github.io/autoptr/ dub: https://code.dlang.org/packages/autoptr Examples: ```d import autoptr.shared_ptr; /// pure nothrow @nogc unittest{ static class Foo{ int i; this(int i)pure nothrow @safe @nogc{ this.i = i; } } static class Bar : Foo{ double d; this(int i, double d)pure nothrow @safe @nogc{ super(i); this.d = d; } } //implicit qualifier cast { SharedPtr!(const Foo) foo = SharedPtr!Foo.make(42); assert(foo.get.i == 42); assert(foo.useCount == 1); const SharedPtr!Foo foo2 = foo; assert(foo2.get.i == 42); assert(foo.useCount == 2); } //polymorphic classes: { SharedPtr!Foo foo = SharedPtr!Bar.make(42, 3.14); assert(foo != null); assert(foo.useCount == 1); assert(foo.get.i == 42); //dynamic cast: { SharedPtr!Bar bar = dynCast!Bar(foo); assert(foo.useCount == 2); assert(bar.get.i == 42); assert(bar.get.d == 3.14); } } //aliasing: { SharedPtr!Foo foo = SharedPtr!Bar.make(42, 3.14); assert(foo.useCount == 1); auto x = SharedPtr!int(foo, ); assert(foo.useCount == 2); assert(x.useCount == 2); assert(*x == 42); } //weak references: { auto x = SharedPtr!double.make(3.14); assert(x.useCount == 1); assert(x.weakCount == 0); auto w = x.weak(); //weak pointer assert(x.useCount == 1); assert(x.weakCount == 1); assert(*w.lock == 3.14); SharedPtr!double.WeakType w2 = x; assert(x.useCount == 1); assert(x.weakCount == 2); assert(w2.expired == false); x = null; assert(w2.expired == true); } //dynamic array { import std.algorithm : all; { auto arr = SharedPtr!(long[]).make(10, -1); assert(arr.length == 10); assert(arr.get.all!(x => x == -1)); } { auto arr = SharedPtr!(long[]).make(8); assert(arr.length == 8); assert(arr.get.all!(x => x == long.init)); } } //static array { import std.algorithm : all; { auto arr = SharedPtr!(long[4]).make(-1); assert(arr.get[].all!(x => x == -1)); } { long[4] tmp = [0, 1, 2, 3]; auto arr = SharedPtr!(long[4]).make(tmp); assert(arr.get[] == tmp[]); } } } /// pure nothrow @safe @nogc unittest{ //make SharedPtr object static struct Foo{ int i; this(int i)pure nothrow @safe @nogc{ this.i = i; } } { auto foo = SharedPtr!Foo.make(42); auto foo2 = SharedPtr!Foo.make!Mallocator(42); //explicit stateless allocator } { import std.experimental.allocator : make, dispose; static void deleter(long* x)pure nothrow @trusted @nogc{ Mallocator.instance.dispose(x); } long* element = Mallocator.instance.make!long; auto x = SharedPtr!long.make(element, ); } { auto arr = SharedPtr!(long[]).make(10); //dynamic array with length 10 assert(arr.length == 10); } } /// nothrow unittest{ //alloc SharedPtr object import std.experimental.allocator : make, dispose, allocatorObject; auto allocator = allocatorObject(Mallocator.instance); { auto x = SharedPtr!long.alloc(allocator, 42); } { static void deleter(long* x)pure nothrow @trusted @nogc{ Mallocator.instance.dispose(x); } long* element = Mallocator.instance.make!long; auto x = SharedPtr!long.alloc(allocator, element, ); } { auto arr = SharedPtr!(long[]).alloc(allocator, 10); //dynamic array with length 10 assert(arr.length == 10); } } ```
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote: On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote: Hello, I allocate some instance of class C manually and then free the memory again: class C { int num; ~this() { writeln("~this"); } } void foo() // @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destroy(c); free(cast(void*) c); c = null; } int main() { foo(); } The code above works well as the destructor of c in class C is called by destroy. Problem is that destroy cannot be used once function foo is annotated with @nogc. There seems to be no way round it. What I want is to keep the function foo annotated with @nogc, but still have the destructor of C be called before free is called. Is there a way to call the destructor through meta programming or some kind of reflection so that I can create some generic function that calls the destructor and then free for any kind of class? Thanks, Bienlein Oops, I just realized that you can also not call emplace when @nogc is present. Well that is at least consistent with not either being able to call destroy ;-). So, I guess this means that you can forget about manually allocating and freeing some instance of a class and using @nogc as well. That's a pitty, @nogc was a good idea. Try this: ```d import std; import core.stdc.stdlib : malloc, free; class C { int num; ~this() @nogc{ debug writeln("~this"); } } void foo() @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destruct(c); free(cast(void*) c); c = null; } void main() { foo(); } //https://github.com/atilaneves/automem/blob/master/source/automem/utils.d void destruct(T)(T obj) if (is(T == class)) { (cast(_finalizeType!T) _finalize)(() @trusted { return cast(void*) obj; }()); } private extern(C){ void rt_finalize(void* p, bool det = true) @trusted @nogc pure nothrow; template _finalizeType(T) { import std.traits: Unqual; static if (is(Unqual!T == Object)) { alias _finalizeType = typeof(_finalize); } else { import std.traits : BaseClassesTuple; import std.meta : AliasSeq; alias _finalizeType = typeof(function void(void* p, bool det = true) { // generate a body that calls all the destructors in the chain, // compiler should infer the intersection of attributes foreach (B; AliasSeq!(T, BaseClassesTuple!T)) { // __dtor, i.e. B.~this static if (__traits(hasMember, B, "__dtor")) () { B obj; obj.__dtor; } (); // __xdtor, i.e. dtors for all RAII members static if (__traits(hasMember, B, "__xdtor")) () { B obj; obj.__xdtor; } (); } }); } } } ```
Re: input range with non copyable element
On Monday, 9 August 2021 at 02:47:40 UTC, Mathias LANG wrote: On Sunday, 8 August 2021 at 18:36:02 UTC, vit wrote: Hello, is there reason why elements of input range must be copyable? By design, not that I can think of. But it is assumed all over the place, unfortunately. You can make your `front` method return by `ref`, but you're still going to get bitten as soon as you do any `std.algorithm`-based operation, as storage classes are not inferred (https://issues.dlang.org/show_bug.cgi?id=9423) and things get passed by value to your delegates by default. The problem can also show up when you `foreach` over a range (https://issues.dlang.org/show_bug.cgi?id=15413). And finally, `std.algorithm` need to support it. So currently you'll have to jump through a lot of hops to get it to work. It'll be much easier to use your own `map` & co to get the job done for the time being. Hopefully at some point in the near future that won't be needed anymore. Look like I am not the first who has this problem: https://issues.dlang.org/show_bug.cgi?id=14478 I copy part of `std.algorithm` I use and change `isInputRange` to: ```d enum bool isInputRange(R) = true && is(typeof(R.init) == R) ///no change && is(ReturnType!((R r) => r.empty) == bool) ///no change && is(typeof((return ref R r) => (auto ref x){}(r.front))) ///Before: , is(typeof((return ref R r) => r.front)) && !is(ReturnType!((R r) => r.front) == void) ///no change && is(typeof((R r) => r.popFront)); ///no change
input range with non copyable element
Hello, is there reason why elements of input range must be copyable? For example this example works and copy ctor is never called: ```d import std.algorithm : map; import std.range; struct Foo{ int i; this(scope ref typeof(this) rhs)pure nothrow @safe @nogc{ //this.i = rhs.i; assert(0, "no copy"); } @disable this(scope const ref typeof(this) rhs)pure nothrow @safe @nogc; } void main(){ Foo[] foos = [Foo(1), Foo(2), Foo(3)]; //this work (copy ctor is never called): { auto tmp = foos .map!((ref foo) => foo.i) .array; } } ``` This doesn't work: ```d void main(){ const(Foo)[] foos = [Foo(1), Foo(2), Foo(3)]; //error: { auto tmp = foos .map!((ref foo) => foo.i) .array; } } ``` Source of my problem is in `isInputRange`: ```d import std.range; import std.traits : ReturnType; alias R = const(Foo)[]; //enum bool isInputRange(R) = static assert(is(typeof(R.init) == R)); ///OK static assert(is(ReturnType!((R r) => r.empty) == bool)); ///OK static assert(is(typeof((return ref R r) => r.front)));///ERROR, copy result of front static assert(!is(ReturnType!((R r) => r.front) == void)); ///OK static assert(is(typeof((R r) => r.popFront))); ///OK ``` Is it possible to make lambda return `auto ref`?
compare types of functions.
Hello, Why this doesn't work: ```d template DestructorType(T){ alias Get(T) = T; alias DestructorType = Get!(typeof((void*){ T tmp; })); } struct Foo{ ~this()@safe{} } ``` ```d void main(){ //Error: static assert: `is(void function(void*) pure nothrow @nogc @safe : void function(void*) @safe)` is false static assert(is(void function(void*)pure nothrow @safe @nogc : DestructorType!Foo)); } ``` but this work: ```d void main(){ alias X = void function(void*)@safe; static assert(is(void function(void*)pure nothrow @safe @nogc : DestructorType!Foo)); } ```
Re: cast to pure function stop work after upgrade
On Monday, 14 June 2021 at 13:31:51 UTC, baby_tiger wrote: this used work for me, after upgrade I get this error. how to fix it ? import std.traits; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } template asPure(string P, alias Fn) if (isFunctionPointer!(typeof())) { enum N = __traits(identifier, Fn); enum string asPure = "private alias " ~ N ~ "_PURE = " ~ typeof().stringof ~ " pure;\n" ~ "__gshared immutable " ~ N ~ "_PURE " ~ P ~"= cast(" ~ N ~ "_PURE) &" ~ N ~ " ;" ; } enum xx = asPure!("VFORMATP", VFORMAT); mixin(xx); void main(){ } reinterpreting cast from `nothrow @nogc extern (C) string(LogLevel level, string file, ulong line, char[] tmp, bool line_break, string tag, string fmt, ...)*` to `pure nothrow @nogc extern (C) string(LogLevel, string, ulong, char[], bool, string, string, ...)*` is not supported in CTFE ```d int foo(int x)@safe{ return x; } /* This is valid. @safe CTFE cast, systemFoo has less restrictive function type. */ auto systemFoo = cast(int function(int)@system) /* ERROR UNSAFE CTFE cast, pureFoo has more restrictive function type. */ //auto pureFoo = cast(void function(int)pure) int function(int)pure pureFoo; shared static this(){ /* This is valid. UNSAFE RUNTIME cast. */ pureFoo = cast(int function(int)pure) } void main(){ assert(pureFoo(42) == 42); } ```
Re: cast to pure function stop work after upgrade
On Monday, 2 August 2021 at 11:28:46 UTC, Tejas wrote: On Monday, 14 June 2021 at 13:31:51 UTC, baby_tiger wrote: [...] It seems to not work at runtime either. Maybe they've made this behaviour illegal now? Hopefully someone answers. ```d import std.traits; import core.stdc.stdarg; enum LogLevel : ubyte { INFO = 0, WARN, ERROR, FATAL, } extern (C) string VFORMAT(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow { return null; } extern (C) string function(LogLevel level, string file, size_t line, char[] tmp, bool line_break, string tag, string fmt, ...) @nogc nothrow pure fp; void main(){ fp = //fails } ``` Try this: ```d void main(){ fp = cast(typeof(fp)) //fails } ```
Re: Destructors can't be @nogc?
On Friday, 23 July 2021 at 20:24:02 UTC, Jim wrote: Hello, I've been playing with D and trying to understand how to work with @nogc. I must be doing something wrong, because even though I tagged the destructor for my class `@nogc`, I'm getting the following error: `.\min.d(27): Error: "@nogc" function "D main" cannot call non-@nogc function "object.destroy!(true, TestClass).destroy` ```D import std.stdio : printf; import core.lifetime : emplace; import core.stdc.stdlib : malloc, free; class TestClass { int x; this(int x) @nogc { printf("TestClass's constructor called\n"); this.x = x; } ~this() @nogc { printf("TestClass's destructor called\n"); } } @nogc void main() { auto size = __traits(classInstanceSize, TestClass); auto memory = malloc(size)[0..size]; TestClass x = emplace!(TestClass)(memory, 1); printf("TestClass.x = %d\n", x.x); destroy(x); free(cast(void*)x); } ``` What is the problem here? Should I not call `destroy`? If so, what should I call instead? You can call function like `destroy` with right attributes for class variable if you known exact type of the class (no base class referece or interface): https://github.com/atilaneves/automem/blob/master/source/automem/utils.d
Re: betterC shared static ctor
On Wednesday, 21 July 2021 at 08:28:22 UTC, Mike Parker wrote: On Wednesday, 21 July 2021 at 08:11:06 UTC, vit wrote: Is it possible to call all shared static ctors in betterC? ```d //-betterC static immutable int i; shared static this(){ i = 42; } extern(C) void main(){ assert(i != 42); } ``` These rely on DRuntime, which is not linked in betterC mode. You'll need to use the `crt_constructor` and `crt_destructor` pragmas: https://dlang.org/spec/pragma.html#crtctor Apply them to any `extern(C) function for static ctor/dtor behavior. Thanks, it works, but now I have different problem. I need call static method for all instantions of template struct from `crt_constructor`. Is there way to iterate over all instantions of template? I need this to work but for all instantions of Foo, not only for Foo!1 a Foo!2 https://run.dlang.io/is/FNqHWh : ```d pragma(crt_constructor) extern(C)void shared_static_this(){ Foo!1.vtable_init(); Foo!2.vtable_init(); //Foo!3.vtable_init(); } extern(C) void main(){ auto foo1 = Foo!1(null); auto foo2 = Foo!2(null); auto foo3 = Foo!3(null); Base* b1 = Base* b2 = Base* b3 = assert(b1.getId() == 1); assert(b2.getId() == 2); //assert(b3.getId() == 3); //vtable is not initialized } struct Vtable{ size_t offset; size_t function(void* ) getId; } struct Base{ immutable Vtable* vptr; this(immutable Vtable* vptr){ assert(vptr !is null); this.vptr = vptr; } size_t getId(){ return vptr.getId((cast(void*)) - vptr.offset); } } struct Foo(size_t id){ static immutable Vtable vtable; Base base; this(typeof(null) nil){ this.base = Base(); } static size_t virtual_getId(Foo* foo){ return id; } static void vtable_init(){ Vtable* vtable = cast(Vtable*) vtable.offset = base.offsetof; vtable.getId = cast(typeof(Vtable.getId))_getId; } } ```
betterC shared static ctor
Is it possible to call all shared static ctors in betterC? ```d //-betterC static immutable int i; shared static this(){ i = 42; } extern(C) void main(){ assert(i != 42); } ```
Re: Not allowed to globally overload operators?
On Tuesday, 20 July 2021 at 06:20:34 UTC, Tejas wrote: ... Initially, I was trying to create the spaceship operator of C++, but we aren't allowed to create new operators ... D has spaceship operator: opCmp (https://dlang.org/spec/operatoroverloading.html#compare).
Re: record: C# like records for D
On Wednesday, 14 July 2021 at 23:16:05 UTC, Dylan Graham wrote: [DUB](https://code.dlang.org/packages/record) [Github](https://github.com/hmmdyl/record) This is record. It aims to implement records similar to what C# has by leveraging D's metaprogramming. [C# Example 1](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/types/records) [C# Example 2](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records). Future steps are going to be adding a record struct; default value support; init-only-setters like in C#, wherein at the end of construction or duplication, the init lambda for the field is called, and the field can be set that once. What adventage has record over normal immutable/const class?
Re: opIndexUnary post in-/decrement how to ?
On Wednesday, 14 July 2021 at 15:19:03 UTC, vit wrote: ```d import std.stdio; struct abc{ int[100] a; struct Proxy{ abc* ptr; const int index; int opUnary(string op : "++")(){ return ++ptr.a[index]; //add missing ++ } } Proxy opIndex(int index)return{ return Proxy(, index); } } void main (){ abc s; s[0]++; ++s[0]; } ```
Re: opIndexUnary post in-/decrement how to ?
On Wednesday, 14 July 2021 at 15:01:45 UTC, wjoe wrote: On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote: On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote: [...] This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ``` This does work for that example but I can't return by reference because what I'm operating on is a part of an int. Some context: ```D struct part_int_t(ARGS...) { int _int; mixin(generate_parts!ARGS); } alias handle_t = part_int_t!("isAllocated", 1, "gen", 8, "index", 23); handle_t handle; static assert (is(handle.typeof_isAllocated): bool)); static assert (is(handle.typeof_gen): ubyte)); static assert (is(handle.typeof_index): uint)); handle[2] = true; handle.gen = 1; handle.index = 1234; assert (handle.isAllocated); assert (handle.gen = 1); assert (handle[0] = 1234); handle++; assert (handle.index == 1235); handle.gen++; assert (handle.gen == 2); handle.reset(); assert (!handle.isAllocated); assert (handle.gen = 3); assert (handle.index = 0); ``` generate_parts!ARGS produces bit masks, getters, setters, opIndex/OpAssign/Unary, etc. and it's impossible to return bits 0-26 of _int by ref. Try something like this: ```d import std.stdio; struct abc{ int[100] a; struct Proxy{ abc* ptr; const int index; int opUnary(string op : "++")(){ return ptr.a[index]; } } Proxy opIndex(int index)return{ return Proxy(, index); } } void main (){ abc s; s[0]++; ++s[0]; } ```
Re: opIndexUnary post in-/decrement how to ?
On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote: On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote: On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote: [...] From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading. If the rewriting part doesn't work with overloading then why aren't we allowed to explicitly overload ```post-increment/decrement``` operators? How else will the OP solve their problem? It must rewrite, otherwise it's impossible (I think). This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ```
Re: opIndexUnary post in-/decrement how to ?
On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote: On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote: On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote: ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;``` Sorry I can't provide something even more concrete. Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ? I think it's a bug, because the following works: ```d import std.stdio; struct abc{ int[100] a; int opIndex(int index){ return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; int[100] a; int temp; writeln (a[20]++); writeln(a[20]); writeln(++s[20]); writeln(s[20]); //writeln(s[0]++);// doesn't work for some reason writeln(s[0]); writeln(s++);//but this works!! writeln(s); } ``` From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
Re: Template arg deduction
On Wednesday, 7 July 2021 at 19:14:52 UTC, Kevin Bailey wrote: I'm trying to use some fairly simple template argument deduction, but maybe I'm not getting the syntax correct. C++ doesn't event blink at something like this, but D is giving me: temptest.d(18): Error: template temptest.func cannot deduce function from argument types !()(bar), candidates are: temptest.d(10):func(T)(foo!T.bar f) I guess D can't crack open a type like that? ``` template foo(T) { class bar { T t; } } void func(T)(// 10 foo!(T).bar f) { } int main() { foo!int.bar fi; func(fi);// 18 } ``` This work: ```d template foo(T){ class bar{ T t; } } void func(alias F : foo!T, T)(F.bar f){ } void main(){ foo!int.bar fi; func(fi); } ```
Re: String front, back return code point/unit
On Wednesday, 23 June 2021 at 15:48:57 UTC, Tejas wrote: On Wednesday, 23 June 2021 at 15:31:04 UTC, vit wrote: Hello, I am implementing @nogc string struct similar to c++ std::basic_string (link https://code.dlang.org/packages/basic_string). C++ string has methods front, back and pop_back returning/deleting code units. D strings has functions (std.range) front, back and popBack returning/deleting code points (autodecoding?). Which behavior is better? I think this video will be helpful: https://www.youtube.com/watch?v=d3qY4dZ2r4w There was also a discussion about this in the group: https://forum.dlang.org/thread/diexjstekiyzgxlic...@forum.dlang.org I wrongly formulated question. My question is not about ranges/iterators but if is good idea autodecoding custom string or not.
String front, back return code point/unit
Hello, I am implementing @nogc string struct similar to c++ std::basic_string (link https://code.dlang.org/packages/basic_string). C++ string has methods front, back and pop_back returning/deleting code units. D strings has functions (std.range) front, back and popBack returning/deleting code points (autodecoding?). Which behavior is better?
@trusted methods
Are asserts enough to make method @trusted or is something like throw exception or return error code necessary? How it work in phobos? Example: ```d struct Slice(T){ private T[] data; this(T[] data){ this.data = data; } inout(T)[] opSlice()inout scope return pure nothrow @safe @nogc{ return data; } inout(T)[] opSlice(size_t b, size_t e)inout scope return pure nothrow @safe @nogc{ return data[b .. e]; } /* Remove subset `slice` from `this.data` `slice` is subset of `this.data`. */ void erase1(scope const(T)[] slice)scope pure nothrow @trusted @nogc{ assert(data.ptr <= slice.ptr); assert((slice.ptr + slice.length) <= (data.ptr + data.length)); //... } // ditto bool erase2(scope const(T)[] slice)scope pure nothrow @trusted @nogc{ if(data.ptr > slice.ptr) return false; if((slice.ptr + slice.length) > (data.ptr + data.length)) return false; //... assert(0, "TODO impl"); } } void main()@safe{ scope slice = Slice!int([1, 2, 3, 4]); scope slice2 = Slice!int([1, 2, 3, 4]); slice.erase2(slice2[1 .. 2]); //return false slice.erase1(slice2[1 .. 2]); //assert error in debug } ```
Re: cannot take address of scope local in safe function
On Sunday, 13 June 2021 at 17:18:46 UTC, ag0aep6g wrote: On Sunday, 13 June 2021 at 16:27:18 UTC, vit wrote: Why I can take address of Foo variable but not Bar? ```d //-dip1000 struct Foo{ private double d; } struct Bar{ private void* ptr; } void main()@safe{ ///this is OK: { scope Foo x; scope ptr = } ///Error: cannot take address of `scope` local `x` in `@safe` function `main`: { scope Bar x; scope ptr = } } ``` `scope` affects indirections (i.e. pointers). `Foo` doesn't contain any indirections, so `scope` doesn't mean anything for it. The compiler just ignores it. It's like you wrote `Foo x;` without `scope`. `Bar` does contain an indirection, so `scope` actually matters and you get the error. Thanks. Is possible create and use scope output range allocated on stack in @safe code? Example: ```d //-dip1000 struct OutputRange{ private bool valid = true; private void* ptr; int count = 0; void put(Val)(auto ref scope Val val){ assert(this.valid == true); this.count += 1; } ~this()scope pure nothrow @safe @nogc{ this.valid = false; } } void main()@safe pure nothrow @nogc{ import std.algorithm : copy; import std.range : only; scope OutputRange or; only(1, 2, 3, 4).copy(); ///Error: cannot take address of `scope` local `or` in `@safe` function `main` assert(or.count == 4); } ```
cannot take address of scope local in safe function
Why I can take address of Foo variable but not Bar? ```d //-dip1000 struct Foo{ private double d; } struct Bar{ private void* ptr; } void main()@safe{ ///this is OK: { scope Foo x; scope ptr = } ///Error: cannot take address of `scope` local `x` in `@safe` function `main`: { scope Bar x; scope ptr = } } ```
Re: GC.addRange in pure function
On Wednesday, 10 February 2021 at 12:17:43 UTC, rm wrote: On 09/02/2021 5:05, frame wrote: On Sunday, 7 February 2021 at 14:13:18 UTC, vitamin wrote: Why using 'new' is allowed in pure functions but calling GC.addRange or GC.removeRange isn't allowed? Does 'new' violate the 'pure' paradigm? Pure functions can only call pure functions and GC.addRange or GC.removeRange is only 'nothrow @nogc'. new allocates memory via the GC and the GC knows to scan this location. Seems like implicit GC.addRange. Yes, this is my problem, if `new` can create object in pure function, then GC.addRange and GC.removeRange is may be pure too. Can I call GC.addRange and GC.removeRange from pure function without problem? (using assumePure(...)() ).
Re: struct constructor with rvalue param of same struct type
On Tuesday, 19 January 2021 at 06:49:06 UTC, Kyle Ingraham wrote: I’m sorry that this isn’t a solution to your problem but your code caught my attention. What is your snippet supposed to do? This is more specific example: https://run.dlang.io/is/W7rd2u import std.traits : CopyTypeQualifiers; struct Ptr(T) if(is(T == struct)){ private void* ptr; static if(is(T == const)) this(ref const typeof(this) x)@trusted{ this.ptr = cast(typeof(this.ptr))x.ptr; } this(ref typeof(this) x)@safe{ this.ptr = x.ptr; } this(ref const typeof(this) x)const @safe{ this.ptr = x.ptr; } this(P : const Ptr!(U), U, this This)(auto ref P x)@trusted if(true //&& !is(R == T) && is(CopyTypeQualifiers!(P, U)* : CopyTypeQualifiers!(This, T)*) ){ this.ptr = cast(typeof(this.ptr))x.ptr; } } struct Foo{ //@disable this(this); } T get_rvalue(T)(){ return T.init; } void main()@safe{ ///normal pointers { const(const(Foo)*) cpcf;///const(Foo*) const(Foo*) cpf1 = cpcf;///OK const(Foo*) cpf2 = get_rvalue!(const(const(Foo)*)); ///OK const(Foo)* pcf1 = cpcf;///OK const(Foo)* pcf2 = const(const(Foo)*).init; ///OK const(Foo)* pcf3 = get_rvalue!(const(const(Foo)*)); ///OK } //wrapped ptr: { const Ptr!(const Foo) cpcf; const Ptr!(Foo) cpf1 = cpcf;///OK const Ptr!(Foo) cpf2 = get_rvalue!(const Ptr!(const Foo)); ///OK Ptr!(const Foo) pcf1 = cpcf;///OK Ptr!(const Foo) pcf2 = const(Ptr!(const Foo)).init; ///OK Ptr!(const Foo) pcf3 = get_rvalue!(const Ptr!(const Foo)); ///ERROR! } }
Re: Why can I call a function with mismatched parameter type?
On Friday, 11 December 2020 at 11:25:22 UTC, Andrey Zherikov wrote: Here is the example: alias f1 = (string ) {}; f1(int .init); alias f2 = (string s) {}; f2(int .init); alias f3 = (int ) {}; f3(string.init); alias f4 = (int i ) {}; f4(string.init); "f1" case compiles successfully and all others are not (error is "is not callable using argument types"). Question is why does f1 case compile? Furthermore even these do compile: f1(float.init); struct S{} f1(S.init); alias f1 = (string ) {} "string" isn't type, but name of variable with generic type: alias f1 = (/*auto type*/ string) {}
Re: Pass lambda into template
On Monday, 3 September 2018 at 09:09:44 UTC, Andrey wrote: Hello, Here is a code with comments: https://run.dlang.io/is/BNl2Up. I don't understand how to pass lambda into template. I get an error: onlineapp.d(18): Error: template instance `qwerty!((i) => "arg" ~ i.to!string ~ "[0] == '?'", "||")` cannot use local __lambda1 as parameter to non-global template qwerty(alias mapper, alias delimiter) Try this: if(mixin(qwerty!((int i) => "arg" ~ i.to!string ~ "[0] == '?'", "||")))
Re: Can't print enum values
On Thursday, 30 August 2018 at 11:34:36 UTC, Andrey wrote: On Thursday, 30 August 2018 at 11:09:40 UTC, vit wrote: [...] I want to create a reusable template for this purpose. Why I can't use "staticMap" so that compiler it self would do this: [...] Just wrap some some symbol "args" with some expression at compile time. It is the same as in C++: [...] D doesn't have expanding like C++ Unfortunately D has only simple automatic expading.
Re: Can't print enum values
On Thursday, 30 August 2018 at 10:41:58 UTC, Andrey wrote: Hello, This code doesn't print enum values: import std.meta; import std.traits; import std.stdio; enum MyEnum : string { First = "F_i_r_s_t", Second = "S_e_c_o_n_d" } alias QW(alias arg) = Alias!(cast(OriginalType!(typeof(arg)))arg); void print(T...)(T args) { writeln(cast(OriginalType!(typeof(args[0])))args[0]); // Works... writeln(QW!(args[0]));// Doesn't work... MUST! writeln(staticMap!(QW, args));// Doesn't work... MUST! } void main() { bool runTimeBool = true; print(MyEnum.First, 7, runTimeBool, MyEnum.Second); } Must print "F_i_r_s_t" and "S_e_c_o_n_d", not just "First" and "Second". args are runtime arguments. import std.experimental.all; enum MyEnum : string { First = "F_i_r_s_t", Second = "S_e_c_o_n_d" } ///alias QW(alias arg) = Alias!(cast(OriginalType!(typeof(arg)))arg); auto QW(T)(const auto ref T x){ return cast(OriginalType!T)x; } void print(T...)(T args) { writeln(cast(OriginalType!(typeof(args[0])))args[0]); // Works... ///writeln(QW!(args[0]));// Doesn't work... MUST! writeln(QW(args[0])); static foreach(alias arg; args){ static if(is(typeof(arg) : MyEnum))write(QW(arg)); else write(arg); } write('\n'); //writeln(staticMap!(QW, args));// Doesn't work... MUST! } void main() { bool runTimeBool = true; print(MyEnum.First, 7, runTimeBool, MyEnum.Second); }
Re: Solving the impossible?
On Wednesday, 29 August 2018 at 19:56:31 UTC, Everlast wrote: On Tuesday, 28 August 2018 at 22:01:45 UTC, Paul Backus wrote: [...] One of the things that makes a good language is it's internal syntactic consistency. This makes learning a language easier and also makes remembering it easier. Determinism is a very useful tool as is abstraction consistency. To say "Just except D the way it is" is only because of necessity since that is the way D is, not because it is correct. (There are a lot of incorrect things in the world such as me "learning" D... since I've been programming in D on and off for 10 years, I just never used a specific type for variadics since I've always use a variadic type parameter) To justify that a poor design choice is necessary is precisely why the poor design choice exists in the first place. These are blemishes on the language not proper design choices. For example, it is necessary for me to pay taxes, but it does not mean that taxes are necessary. Actual syntax work with more then slices...: import std.algorithm : equal; void foo(size_t N)(int[N] args...){ assert(args[].equal([1, 2, 3, 4, 5])); } void main(){ foo(1, 2, 3, 4, 5); }
Re: Create constraint for each parameter in template arg pack
On Tuesday, 28 August 2018 at 12:28:19 UTC, Andrey wrote: Hello, Let we have two variadic templates: template Qwerty(Values...) {} template Qaz(alias type, Data...) {} Now I want to add a constraint to "Qwerty" so that each type in "Values" pack must be a "Qaz" template. I don't care about values of "type" or "Data" in "Qaz". How to do it in D? Generic solution: template Qwerty(Values...) if(allSatisfy!(isInstanceOf!Qaz, Values)){ } class Qaz(alias type, Data...) {} import std.meta : allSatisfy; public import std.traits : isInstanceOf; template isInstanceOf(alias T){ import std.traits : impl = isInstanceOf; static enum isInstanceOf(alias X) = impl!(T, X); static enum isInstanceOf(X) = impl!(T, X); }
Re: Create constraint for each parameter in template arg pack
On Tuesday, 28 August 2018 at 12:28:19 UTC, Andrey wrote: Hello, Let we have two variadic templates: template Qwerty(Values...) {} template Qaz(alias type, Data...) {} Now I want to add a constraint to "Qwerty" so that each type in "Values" pack must be a "Qaz" template. I don't care about values of "type" or "Data" in "Qaz". How to do it in D? import std.meta : allSatisfy; template Qwerty(Values...) if(allSatisfy!(isQaz, Values)){ } template Qaz(alias type, Data...) {} enum isQaz(alias Q : Qaz!Args, Args...) = true; enum isQaz(Args...) = false; alias Foo = Qwerty!(Qaz!(i => i), Qaz!(i => i), Qaz!(i => i));
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 12:54:59 UTC, SG wrote: On Monday, 27 August 2018 at 03:21:04 UTC, rikki cattermole wrote: Templates make it the easiest way, since common patterns, like arrays, classes and pointers have the exact same null check syntax. I see. That code is only for classes. C# also has structs which are a value type. Which it would not work for. The same thing for struct in C# Struct S{ public int? i; } S.i == null; // This works nicely. You don't need isNull function for Nullable because it has a method called it. That will be preferred (hence I specifically used isNull as the name). For Variant, use hasValue. bool isNull(Variant value) { return !value.hasValue; } The problem I'm trying to solve is beyond that. This is just an example. But bear with me, right now all I want is a function to check the value from 'a' type and return if it is null. The type could be a: Class, Struct, a Basic data type, Variant, Nullable and so. And what I see, these types has different behaviors, while in C# at least for this same case, I would write the same thing in few lines to perform it, in D I found very hard. Isn't counter intuitive the way D works? Because for each type Class/Nullable you check with .isNull, for Variant with .hasValue, for string (variable is null). Thanks. hasValue isn't equivalent of isNull or is null. 'null' is valid value in Variant: import std.variant; Variant v; v = null; assert(v.hasValue);//v has value assert(v.get!(typeof(null)) is null); //value in v is null Nullable!T.isNull isn't equivalent of is null: int* i = null; Nullable!(int*) ni; ni = i; assert(ni.isNull == false); ///ni has value assert(ni is null); ///ni value is null string is null isn't equivalent of empty: string str = "test"; str = str[0 .. 0]; assert(str !is null); ///str isn't null assert(str.empty); ///str is empty
Re: Patterns to avoid GC with capturing closures?
On Friday, 24 August 2018 at 15:18:13 UTC, Peter Alexander wrote: Consider this code, which is used as an example only: auto scaleAll(int[] xs, int m) { return xs.map!(x => m * x); } As m is captured, the delegate for map will rightly allocate the closure in the GC heap. In C++, you would write the lambda to capture m by value, but this is not a facility in D. I can write scaleAll like this: auto scaleAll(int[] xs, int m) @nogc { return repeat(m).zip(xs).map!(mx => mx[0] * mx[1]); } So that repeat(m) stores m, but it is quite hacky to work like this. I could write my own range that does this, but this is also not desirable. Are there any established patterns, libraries, or language features that can help avoid the GC allocation in a principled way here? I try pack/unpack solution, but it looks horrible. Problem is when every part of chain (filter, map, ...) need capture different variables. I implement modified version of algorithm (filter, map, until, tee): https://dpaste.dzfl.pl/929a7af4e87f You don't need reimplement all of std.algorithm, only parts which can be in the middle of chain, things like any, all, each, count can be ignored. example: void main()@nogc{ import std.algorithm : any; import std.range : iota; import util.algorithm : map, filter; const int a = 1, b = 2, c = 3; const x = iota(0, 10) .map!((x, i) => x*i)(a) ///map!((x) => x*a) .map!((x, i) => x*i)(b) ///map!((x) => x*b) .filter!((x, i) => x%i)(c)///filter!((x) => x%c) .any!(x => x % c); assert(x == true); }
Re: Make function alias
On Monday, 20 August 2018 at 13:22:02 UTC, Andrey wrote: On Monday, 20 August 2018 at 13:14:14 UTC, Andrey wrote: Mistake... this is: static void log(bool newline = true)(string text) { alias print(T...) = newline ? : _file.print(text); text.print(); } static void log(bool newline = true)(string text) { static if(newline)alias print = writeln; else alias print = write; _file.print(text); text.print(); }
Re: Is @safe still a work-in-progress?
On Friday, 17 August 2018 at 13:02:20 UTC, Jonathan M Davis wrote: On Friday, August 17, 2018 6:30:26 AM MDT Atila Neves via Digitalmars-d wrote: On Friday, 17 August 2018 at 11:37:54 UTC, rikki cattermole wrote: > On 17/08/2018 11:33 PM, Atila Neves wrote: >> . Good luck figuring out why your template functions aren't >> @safe and coaxing the compiler to tell you why it's >> inferring the attributes it is. Bonus points if it's a >> Phobos function so you can't slap `@safe` on its definition. > > Sure you can. It's a template so it'll be initialized as its > required. > > I've done that to fix a bug in druntime before and in my own > libraries. It's not easy though. You have to either be building your own phobos or sudo editing files in /usr/include. You can, but it's a pain. Then there's finding out exactly where in a chain of 10 template functions that it became @system... The reality of the matter is that you tend to have to be very motivated to make your code @safe if you're doing much with templates (the same with other attributes such as pure). And sadly, it can quickly get to the point that it just feels like it's not worth it in spite of the fact that there is definitely value to be had in using them. I wonder what it would take to make it so that the compiler could actually tell you where in the function call chain it first becomes @system. - Jonathan M Davis Does -dip1000 affect alias template parameters and closures? example: import std.experimental.all; void main()@safe @nogc{ int i = 2; const x = iota(0, 10) .filter!((x)scope => x == i) .map!((x)scope => x * x) .front; assert(x == 4); } onlineapp.d(4): Error: function `D main` is @nogc yet allocates closures with the GC onlineapp.d(8):onlineapp.main.__lambda1 closes over variable i at onlineapp.d(5)
Re: Is @safe still a work-in-progress?
On Friday, 17 August 2018 at 07:50:32 UTC, Jonathan M Davis wrote: On Friday, August 17, 2018 1:19:25 AM MDT Peter Alexander via Digitalmars-d wrote: [...] That particular bug is a duplicate of https://issues.dlang.org/show_bug.cgi?id=8838, which was closed as fixed based on the fact that -dip1000 fixes the problem by treating marking the slice of a static array with scope. It's still quite broken without -dip1000 though. [...] What's the state of -dip1000?
Re: Concat enum of strings into one string
On Tuesday, 14 August 2018 at 14:37:33 UTC, Andrey wrote: On Tuesday, 14 August 2018 at 14:07:23 UTC, Timoses wrote: Here's one version: template StringEnumValues(alias Enum) { import std.traits : EnumMembers; string[] StringEnumValues() { string[] enumValues; static foreach (member; EnumMembers!Enum) enumValues ~= member; return enumValues; } } import std.string : join; pragma(msg, StringEnumValues!Type.join(" ")); Thank you. Hmm, I thought that standard library already has this stuff. import std.traits : EnumMembers; import std.string : join; import std.algorithm : map; pragma(msg, [EnumMembers!Type].map!(x => cast(string)x).join(" "));
Re: sumtype 0.5.0
On Thursday, 9 August 2018 at 01:04:43 UTC, Paul Backus wrote: On Thursday, 9 August 2018 at 00:11:22 UTC, Seb wrote: On Thursday, 9 August 2018 at 00:07:05 UTC, Seb wrote: (It uses the version from DUB and updates itself once daily, but somehow dub still lists 0.4.1 at the moment) It looks like you didn't push the git tag to GitHub: https://github.com/pbackus/sumtype/releases One of these days, I'll learn. Should be there now. ignore the message with opAssign, my version doesnt work :)
Re: sumtype 0.5.0
On Thursday, 9 August 2018 at 01:04:43 UTC, Paul Backus wrote: ... @safe opAssign can call @system postblit: bool moved = false; struct S{ this(this)@system{ moved = true; } } void main()@safe{ auto st = SumType!(S).init; st = S.init; assert(moved == true); } change: () @trusted { moveEmplace(rhs, storage.values[i]); }(); to: moveEmplace(rhs, *(() @trusted => [i])());
Re: sumtype 0.5.0
On Thursday, 9 August 2018 at 01:04:43 UTC, Paul Backus wrote: On Thursday, 9 August 2018 at 00:11:22 UTC, Seb wrote: On Thursday, 9 August 2018 at 00:07:05 UTC, Seb wrote: (It uses the version from DUB and updates itself once daily, but somehow dub still lists 0.4.1 at the moment) It looks like you didn't push the git tag to GitHub: https://github.com/pbackus/sumtype/releases One of these days, I'll learn. Should be there now. SumType without initialization doesn't fail if first type has @disabled this(). In SumType need be something like this: struct SumType(...){ ///... static if(Types.length > 0 && __traits(compiles, (){Types[0] tmp;}()) == false){ ///Types[0] has disabled this() @disable this(); } /// } method toString is not template. (why is there in the first place?) SumType can have zero TypeArgs but then tryMatch fail: auto st = SumType!(); st.tryMatch!((_) => 1); //fail at compile time with bad error message. in matchImpl can by something like this: static if(Types.length == 0){ static if(exhaustive) { static assert(0, "No value to match"); } else { throw new MatchException("No value to match"); } } else{ ///... } or: struct SumType(TypeArgs...) if(TypeArgs.length > 0){ }
Re: sumtype 0.5.0
On Wednesday, 8 August 2018 at 20:54:13 UTC, Paul Backus wrote: SumType is a generic sum type for modern D. It is meant as an alternative to `std.variant.Algebraic`. Features: - Pattern matching, including support for structural matching (*) - Self-referential types, using `This` - Works with `pure`, `@safe`, `@nogc`, and `immutable` (*) - Zero runtime overhead compared to hand-written C - No heap allocation - Does not rely on runtime type information (`TypeInfo`) (*) Starred features (*) are those that are missing from `Algebraic`. Code examples are available in the documentation (linked below). New since the last announced version, 0.3.0: - Types with destructors and postblits are now handled correctly. - Unreachable handlers in `match` calls are now a compile-time error. - `match` handlers can now operate on the stored value by reference. - A new method, `tryMatch`, allows for non-exhaustive pattern matching. - Various small improvements to the documentation. Documentation: https://pbackus.github.io/sumtype/sumtype.html DUB: https://code.dlang.org/packages/sumtype Github: https://github.com/pbackus/sumtype Nice, but destructor SumType.~this() can call destroy on reference type like class: bool destructed = false; class C{ ~this(){ destructed = true; } } struct S{ ~this(){ } } void main(){ auto c = new C; { auto st = SumType!(C, S)(c); } assert(destructed == true); }
Re: float/double to string (pure nothrow @nogc)
On Wednesday, 8 August 2018 at 17:40:11 UTC, ketmar wrote: vit wrote: Hello, is in phobos some function which convert float/double to string and is pure @nogc and nothrow? i don't think that you can make it `pure`, but you certainly can make it `nothrow`, `@nogc` and ctfe-able. it's dangerous to go alone! take this[0]. [0] http://repo.or.cz/iv.d.git/blob_plain/HEAD:/ctfefloat.d thanks, that code can be modified to pure nothrow @nogc @safe. Is that lib ok? Is little complicated...