Re: container vs standard array
On Tuesday, 19 September 2023 at 00:34:01 UTC, vino wrote: Hi All, I am trying to understand as to why the below code is throwing error Code ``` import std.stdio: writeln; import std.container.array; void main () { //auto a = Array!string("Aname"); // throws error auto b = Array!char("Bname");// works auto c = Array!string("Aname", "Bname"); // works //writeln(a); writeln("Container Array :", b); writeln("Container Array :", c); writeln(); string[] d = ["Dname"]; // works string[] e = ["Dname", "Ename"]; // works writeln("Standard Array :", d); writeln("Standard Array :", e); } ``` From, Vino Looks to me like when it receives a single range it expects the elements of that range to match the type. If I am correct in the first one if you replace the "Aname" by ["Aname"] it should work
Re: mutable pointers as associative array keys
On Monday, 10 April 2023 at 18:14:56 UTC, John Colvin wrote: It seems that it isn't possible, am I missing something? alias Q = int[int*]; pragma(msg, Q); // int[const(int)*] Also, is this documented somewhere? It seems to be so (which is strange) and I can't image it is by design since you can do this: ```d static struct Pointer(T) { T* val; } int[Pointer!int] f; pragma(msg,typeof(f)); int* val = new int; *val = 5; f[Pointer!int(val)] = 12; *val = 6; f[Pointer!int(val)].writeln; //12 ```
Re: Is there a way to get the name of the current function?
On Tuesday, 7 March 2023 at 22:11:49 UTC, rempas wrote: For example, in the given code: ```d void my_function() { import std.stdio; writeln("The name of the function is: ", ); } ``` Is there something to put in the place of `` to get the name of the function? Yes, see here: https://dlang.org/spec/expression.html#specialkeywords
Re: Why not allow elementwise operations on tuples?
On Monday, 16 January 2023 at 08:30:15 UTC, Sergei Nosov wrote: On Friday, 13 January 2023 at 15:27:26 UTC, H. S. Teoh wrote: [...] Yeah, that's clear that such an implementation is rather straightforward. Although, I'm a bit confused with your implementation - 1. it doesn't seem to use tuples behind the scenes despite your claim (it uses static array) 2. `alias impl this;` introduces some unexpected interactions (e.g. `~` and `toString` are "intercepted" by the array implementation and yield "wrong" results). Anyway, my original question was primarily about reasoning - why there's no implementation specifically for `std.Tuple`? If it's a "feature, not a bug" - what's the best way to provide an implementation on the client side? I guess such a method wouldn't be particularly generic since a tuple does not need to consist of types that have the same operations e.g. Tuple!(int,string) etc
Re: "Little Scheme" and PL Design (Code Critique?)
On Thursday, 17 November 2022 at 22:05:45 UTC, jwatson-CO-edu wrote: I just pushed a D implementation of "[Little Scheme](https://mitpress.mit.edu/9780262560993/the-little-schemer/)", which is a limited educational version of [Scheme](https://en.wikipedia.org/wiki/Scheme_(programming_language)), to [GitHub](https://github.com/jwatson-CO-edu/SPARROW). [...] I think using the d garbage collector is a good idea. (I have written two implementations of scheme like languages one in c and one in d, and I found it a great pleasure not to have to write a GC for the d one). On the other hand if you want to write one there is no obstruction doing so in d.
Re: Find in assoc array then iterate
On Friday, 21 October 2022 at 22:03:53 UTC, Kevin Bailey wrote: I'm trying to do this equivalent C++: unordered_map map; for (auto i = map.find(something); i != map.end(); ++i) ...do something with i... in D, but obviously with an associative array. It seems that it's quite easy to iterate through the whole "map", but not start from the middle. Am I missing something obvious (or not so obvious) ? You can build a map using a red black tree. Then you should be able to do what you want. https://dlang.org/phobos/std_container_rbtree.html
Re: C function taking two function pointers that share calculation
On Wednesday, 14 September 2022 at 17:23:47 UTC, jmh530 wrote: There is a C library I sometimes use that has a function that takes two function pointers. However, there are some calculations that are shared between the two functions that would get pointed to. I am hoping to only need to do these calculations once. [...] Maybe others know better but I would have thought the only way is to use globals to do this. Often c libraries that I have used get round this by taking a function and a pointer and then the library calls your function on the pointer simulating a d delegate.
Re: Casting rules
On Friday, 26 August 2022 at 21:18:15 UTC, ag0aep6g wrote: On Friday, 26 August 2022 at 20:42:07 UTC, JG wrote: [...] Casting immutable/const away: https://dlang.org/spec/const3.html#removing_with_cast The cast itself allowed. Mutating the data is not. Casting to immutable: https://dlang.org/spec/const3.html#creating_immutable_data The cast is allowed as long as you don't mutate the data afterwards. Conversion to const doesn't need a cast. Mutable and immutable both implicitly convert to const. Thank you very much.
Casting rules
Where can I find rules about casting. e.g. I assume casting away immutable is undefined behavior (or implementation defined behavior). What about casting to immutable (I would expect at most it only to be allowed if your type has no references e.g. ints okay but int[] not etc.) Casting const away (probably not allowed)? Casting to const (probably allowed). Anyhow guessing aside where can I find the rules?
Re: typeof(func!0) != typeof(func!0())
On Monday, 22 August 2022 at 04:39:18 UTC, Andrey Zherikov wrote: I have this simple code: ```d struct U { auto ref func(int i)() { return this; } } void main() { { alias type = typeof(U().func!0); pragma(msg, type); // pure nothrow @nogc ref @safe U() return pragma(msg, is(type : U)); // false auto u = U().func!0; pragma(msg, typeof(u)); // U } { alias type = typeof(U().func!0()); pragma(msg, type); // U pragma(msg, is(type : U)); // true auto u = U().func!0(); pragma(msg, typeof(u)); // U } } ``` Why does `typeof(U().func!0)` != `U`? How can I check that the returned value has type `U` in this case? Why not just change to: alias type = typeof(U().func!0());
Re: This code completely breaks the compiler:
On Friday, 19 August 2022 at 03:13:03 UTC, Ruby The Roobster wrote: On Friday, 19 August 2022 at 03:10:38 UTC, Ruby The Roobster wrote: This snippet compiles. Even if `dsds` and `sadsad` are defined nowhere, this code compiles. [SNIP] The reason why this compiles is because of the varidic template parameter, `Mtypes`. Either there is something I'm missing, or the compiler completely breaks when it sees varidic template arguments. The only way to get the code to not compile is to actually call the function. I think it might help to post the entire code you think should not compile (which does). I guess you are aware that templated code is only "fully checked" when it is instantiated. E.g. this will compile. ```d import std; auto nonsense(T)(T t) { return 5+"six"; } void main() { } ```
Re: Better way to achieve the following
On Tuesday, 21 June 2022 at 17:15:02 UTC, Steven Schveighoffer wrote: On 6/21/22 1:09 PM, JG wrote: Thoughts? Use a pointer? Especially if you are using `.method` calls, this just works seamlessly. -Steve Thanks for the suggestion. My immediate reaction is that for `.method` calls I would agree, but for assignments it is slightly less pleasant. Perhaps it is the best option.
Better way to achieve the following
Suppose we are often writing something like ```d theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex]=x; ``` One would like to something like ```d alias shortName = theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex]; shortName = x; ``` but you can't alias an expression. You can do ```d (ref shortName) { shortName = x; }(theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex]); ``` but that doesn't read well since the ``definition'' of shortName comes at the end. Another option is ```d auto aliasAs(alias f,T)(ref T x) { return f(x); } theFirstName[theFirstIndex].theSecondName[theSecondIndex].thirdName[theThirdIndex].aliasAs! (ref shorName) { shortName = x; } ``` Thoughts?
Re: Failure due to memcpy being called at compile time
On Tuesday, 21 June 2022 at 01:39:43 UTC, Paul Backus wrote: On Tuesday, 14 June 2022 at 05:35:46 UTC, JG wrote: On Monday, 13 June 2022 at 21:45:39 UTC, Paul Backus wrote: The call to `move` is coming from `SumType.opAssign`: https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681 I've filed a bugzilla issue for this here: https://issues.dlang.org/show_bug.cgi?id=23182 Thanks, for doing this. Update: a new release of [the `sumtype` package on code.dlang.org][1] is available that includes the fix for this bug. `std.sumtype` will be fixed in the next Phobos release, 2.100.1. [1]: https://code.dlang.org/packages/sumtype That is great. Is this a work around the CFE bug?
Re: Whats the proper way to write a Range next function
On Wednesday, 15 June 2022 at 17:30:31 UTC, JG wrote: On Wednesday, 15 June 2022 at 13:52:24 UTC, Christian Köstlin wrote: the naive version would look like ```d auto next(Range)(Range r) { r.popFront; return r.front; } ``` But looking at a mature library e.g. https://github.com/submada/btl/blob/9cc599fd8495215d346ccd62d6e9f1f7ac140937/source/btl/vector/package.d#L229 is looks like there should be tons of annotations/attributes on it. Kind regards, Christian I not sure of your use case. But you need to check if the range is empty before and after calling popFront (and decide what to if it is). Also unless you want the original range passed in mutated you should call save (assuming you have a forward range) before calling your next or you need to modify next so it calls save. This is what I would write for next (which should only be called after checking if the range is empty). It produces a range whose front points at the next element. ```d auto next(Range)(Range r) { auto ret = r.save; ret.popFront; return ret; } ```
Re: Whats the proper way to write a Range next function
On Wednesday, 15 June 2022 at 13:52:24 UTC, Christian Köstlin wrote: the naive version would look like ```d auto next(Range)(Range r) { r.popFront; return r.front; } ``` But looking at a mature library e.g. https://github.com/submada/btl/blob/9cc599fd8495215d346ccd62d6e9f1f7ac140937/source/btl/vector/package.d#L229 is looks like there should be tons of annotations/attributes on it. Kind regards, Christian I not sure of your use case. But you need to check if the range is empty before and after calling popFront (and decide what to if it is). Also unless you want the original range passed in mutated you should call save (assuming you have a forward range) before calling your next or you need to modify next so it calls save.
Re: Bug in dmd?
On Tuesday, 14 June 2022 at 23:56:58 UTC, Andrey Zherikov wrote: On Tuesday, 14 June 2022 at 21:44:48 UTC, Dukc wrote: No idea. The functions seems indeed to be exactly the same, so I assume this is a DMD bug. It cannot be a bug in `std.sumtype`, since that would trigger in both of the templates. This definitely triggers some bug in DMD because this `private void printHelp ...` function is not really `private` as it's called from [another module](https://github.com/andrey-zherikov/argparse/blob/bug/source/argparse/internal.d#L786) and DMD doesn't catch this. I tried to reproduce it but wasn't able (I guess it is some interplay with the rest of your code): ```d import std.sumtype; alias CC = SumType!(AA,BB); struct AA {} struct BB { CC[] c; } private void ppp(T, Output)(auto ref Output output, in CommandArguments!T cmd, in Config config) { auto cc = CC(AA()); // (1) } private void printHelp(T, Output)(auto ref Output output, in CommandArguments!T cmd, in Config config) { auto cc = CC(AA()); // (2) } void printHelp(T, Output)(auto ref Output output, in Config config) { ppp(output, CommandArguments!T(config), config); printHelp(output, CommandArguments!T(config), config); } struct CommandArguments(T) { T x; } struct Config {} void main() { string test; Config config; CommandArguments!int commandArguments; printHelp!(int,string)(test,commandArguments,config); } ```
Re: Bug?
On Tuesday, 14 June 2022 at 19:49:39 UTC, Steven Schveighoffer wrote: On 6/14/22 3:35 PM, JG wrote: Hi, Is this a bug? ```d import std; template test(alias f) { auto test(I)(I i) { return f(i); } } void main() { alias t = test!(x=>x+1); 1.t.writeln; //<--Doesn't compile 1.test!(x=>x+1).writeln; t(1).writeln; } ``` Not a bug. Local symbols can't be used as UFCS functions. -Steve Thanks very much. I left wondering why that design decision was made.
Bug?
Hi, Is this a bug? ```d import std; template test(alias f) { auto test(I)(I i) { return f(i); } } void main() { alias t = test!(x=>x+1); 1.t.writeln; //<--Doesn't compile 1.test!(x=>x+1).writeln; t(1).writeln; } ```
Re: Failure due to memcpy being called at compile time
On Monday, 13 June 2022 at 21:45:39 UTC, Paul Backus wrote: On Monday, 13 June 2022 at 19:48:06 UTC, JG wrote: Hi, I reduced my code to the following. Could anyone help me to discover why the line marked with //THIS LINE causes memcpy to be called, and how can I avoid this? Reduced further: ```d import std.sumtype; struct Tuple { void opAssign(Tuple rhs) {} } alias ParseErrorOr = SumType!Tuple; auto parserOr() { ParseErrorOr cur; cur = ParseErrorOr(Tuple()); return cur; } void main() { enum a = parserOr(); } ``` The call to `move` is coming from `SumType.opAssign`: https://github.com/dlang/phobos/blob/v2.100.0/std/sumtype.d#L681 I've filed a bugzilla issue for this here: https://issues.dlang.org/show_bug.cgi?id=23182 Thanks, for doing this.
Re: Failure due to memcpy being called at compile time
On Monday, 13 June 2022 at 20:25:00 UTC, Steven Schveighoffer wrote: On 6/13/22 4:09 PM, JG wrote: Thanks. It seems to be something to do with the variadic template since this works: ```d import std; struct ParseError { string msg; } alias ParseErrorOr(T) = SumType!(ParseError,T); auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); } auto parserOr(I,alias f, alias g)(I i) { auto cur = f(i); if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } return g(i); } auto parseNothing(I)(I i) { return parseErrorOr(tuple(i[0..0],i)); } void main() { enum a = parserOr!(string,parseNothing!string,parseNothing!string)("hello"); } ``` Given that it's inside `moveEmplace`, I'd suspect something deep in `SumType`. -Steve Really strange. I can also work around it like this: ```d auto parserOr(I,fs...)(I i) if(fs.length>=2) { auto cur = fs[0](i); if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } static if(fs.length==2) { return fs[1](i); } else { return parserOr!(I,fs[1..$])(i); } } ```
Re: Failure due to memcpy being called at compile time
On Monday, 13 June 2022 at 19:59:16 UTC, Steven Schveighoffer wrote: On 6/13/22 3:48 PM, JG wrote: Hi, I reduced my code to the following. Could anyone help me to discover why the line marked with //THIS LINE causes memcpy to be called, and how can I avoid this? ```d import std; struct ParseError { string msg; } alias ParseErrorOr(T) = SumType!(ParseError,T); auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); } auto parserOr(I,fs...)(I i) { alias RetType = typeof(fs[0](I.init)); auto cur = RetType(ParseError.init); foreach(f;fs) { if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } cur = f(i); //THIS LINE } return cur; } auto parseNothing(I)(I i) { return parseErrorOr(tuple(i[0..0],i)); } void main() { enum a = parserOr!(string,parseNothing!string,parseNothing!string)("hello"); } ``` Happens in `moveEmplaceImpl` in `core.lifetime`. Somebody is calling that. https://github.com/dlang/druntime/blob/v2.099.1/src/core/lifetime.d#L2192 No stack trace though, that would actually be nice to have in the CTFE interpreter. I imagine if you solved that call, you would get out to a place where it tries to cast to the actual type and fail there instead. -Steve Thanks. It seems to be something to do with the variadic template since this works: ```d import std; struct ParseError { string msg; } alias ParseErrorOr(T) = SumType!(ParseError,T); auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); } auto parserOr(I,alias f, alias g)(I i) { auto cur = f(i); if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } return g(i); } auto parseNothing(I)(I i) { return parseErrorOr(tuple(i[0..0],i)); } void main() { enum a = parserOr!(string,parseNothing!string,parseNothing!string)("hello"); } ```
Failure due to memcpy being called at compile time
Hi, I reduced my code to the following. Could anyone help me to discover why the line marked with //THIS LINE causes memcpy to be called, and how can I avoid this? ```d import std; struct ParseError { string msg; } alias ParseErrorOr(T) = SumType!(ParseError,T); auto parseErrorOr(T)(T x) { return ParseErrorOr!T(x); } auto parserOr(I,fs...)(I i) { alias RetType = typeof(fs[0](I.init)); auto cur = RetType(ParseError.init); foreach(f;fs) { if(cur.match!((ParseError e)=>false,_=>true)) { return cur; } cur = f(i); //THIS LINE } return cur; } auto parseNothing(I)(I i) { return parseErrorOr(tuple(i[0..0],i)); } void main() { enum a = parserOr!(string,parseNothing!string,parseNothing!string)("hello"); } ```
Re: Generating unique identifiers at compile time
On Sunday, 12 June 2022 at 18:45:27 UTC, Paul Backus wrote: On Thursday, 9 June 2022 at 21:20:27 UTC, JG wrote: [...] [...] [...] Here's a `gensym` implementation I came up with a while back: ```d enum gensym = q{"_gensym" ~ __traits(identifier, {})["__lambda".length .. $]}; // Works multiple times on the same line pragma(msg, mixin(gensym)); pragma(msg, mixin(gensym)); ``` This takes advantage of the fact that the compiler generates a unique identifier for every lambda function it encounters. While you can't actually use those identifiers in your code, they are visible in error messages and can be accessed via `__traits(identifier)`. Hi, This is great thanks.
Re: Generating unique identifiers at compile time
On Friday, 10 June 2022 at 06:17:54 UTC, bauss wrote: On Thursday, 9 June 2022 at 23:50:10 UTC, user1234 wrote: There's [been attempts] to expose it, exactly so that users can generate unique names, but that did not found its path in the compiler. [been attempts]: https://github.com/dlang/dmd/pull/10131 You can generate unique names actually by using CTFE RNG, so it's not really necessary to have it exposed to achieve that. See my hacky example of hidden class members here: https://forum.dlang.org/thread/siczwzlbpikwlevvi...@forum.dlang.org Thanks for the answers. In my particular I found a way to generate a new depending on the the left hand side.
Generating unique identifiers at compile time
Hi, As an experiment I have implemented the following kind of pattern matching (by parsing the part of the string before '='). ```d struct S { int x; int y; } struct T { int w; S s; } void main() { mixin(matchAssign(q{auto T(first,S(second,third)) = T(1,S(2,3));})); first.writeln; // 1 second.writeln; // 2 third.writeln; // 3 } ``` In doing so I wanted to produce unique identifiers (something like gensym in racket.) I did this in a very hacky way: ```d auto hopefullyUniqueName(size_t n, size_t line=__LINE__) { return format!"var___%s%s"(n,line); } ``` where I pass in the hash of the right hand side in the assignment in place of n. Is there some way to ask the compiler for a unique name or a better way of achieving this?
Re: static assert("nothing")
On Tuesday, 31 May 2022 at 08:51:45 UTC, realhet wrote: Hi, In my framework I just found a dozen of compile time error handling like: ...else static assert("Invalid type"); This compiles without error. And it was useless for detecting errors because I forgot the first "false" or "0" parameter. I think it is because of the weird case of "every string casted to bool is true". There is an example in Phobos also: https://github.com/dlang/phobos/blob/master/std/uni/package.d at line 8847: static assert("Unknown normalization form "~norm); It is easy to make this mistake, but does static assert(string) has any meaningful use cases? I was going to suggest to do something like: ```d import std; string compileError(string msg) { import std.format; return format("static assert(0,%(%s%));",[msg]); } auto doGreatThings(T)(T x) { static if(is(T==int)) { return "great things!"; } else mixin(compileError("Invalid type.")); } void main() { doGreatThings!int(123).writeln; doGreatThings!string("oh dear").writeln; } ``` But (a) why should you need to and (b) this makes the message more obscure. onlineapp.d-mixin-14(14): Error: static assert: "Invalid type." onlineapp.d(20):instantiated from here: `doGreatThings!string`
Bug?
Hi, I was reading the source of std.algorithm cache and saw some code that didn't make sense to me with a comment indexing the [bug report](https://issues.dlang.org/show_bug.cgi?id=15891). Could anyone help to understand if this code is really necessary (meaning I have some misconception) or is it a work around a compiler bug. Here is the code simplified down as much as I could: ```d import std.range.primitives; import std.traits; struct _Cache(R) { private { alias UE = Unqual!(ElementType!R); R source; UE caches; } this(R range) { source = range; if (!range.empty) { caches = source.front; }/* else { //Uncomment "else" to fix broken version (see below) caches = UE.init; }*/ } } struct _ConstructorlessCache(R) { private { alias UE = Unqual!(ElementType!R); R source; UE caches; } } auto constructorlessCache(Range)(Range range) { auto ret = _ConstructorlessCache!Range(range); if (!range.empty) { ret.caches = range.front; } return ret; } auto cache(Range)(Range range) { return _Cache!(Range)(range); } auto map(alias fun, Range)(Range range) { return MapResult!(fun,Range)(range); } struct MapResult(alias fun, Range) { alias R = Unqual!Range; R _input; bool empty() { return _input.empty; } auto ref front() { return fun(_input.front); } } void main() { /* Won't compile unless part near top is uncommented. Gives: onlineapp.d(21): Error: one path skips field `caches` onlineapp.d(75): Error: template instance `onlineapp.cache!(MapResult!(__lambda1, int[]))` error instantiating */ //[1].map!(x=>[x].map!(y=>y)).cache; //What seems to be essentially the same code compiles fine [1].map!(x=>[x].map!(y=>y)).constructorlessCache; } ```
Re: Allocate a string via the GC
On Monday, 23 May 2022 at 11:39:22 UTC, Adam D Ruppe wrote: On Monday, 23 May 2022 at 09:38:07 UTC, JG wrote: Hi, Is there any more standard way to achieve something to the effect of: ```d import std.experimental.allocator; string* name = theAllocator.make!string; ``` Why do you want that? Easiest way I know of is to just wrap it in a struct, then `new that_struct`, which is also a better way for all the use cases I know but those use cases are pretty rare so there's probably a better way to do what you're trying to do. I am writing an interpreter and I needed access to a string via a pointer of type void* I ended up wrapping it in a struct since I needed another value anyway. Seems odd that one can't do it in a less unusual way. Thanks.
Allocate a string via the GC
Hi, Is there any more standard way to achieve something to the effect of: ```d import std.experimental.allocator; string* name = theAllocator.make!string; ```
Re: Question on shapes
On Tuesday, 17 May 2022 at 00:10:55 UTC, Alain De Vos wrote: Let's say a shape is ,a circle with a radius ,or a square with a rectangular size. I want to pass shapes to functions, eg to draw them on the screen, draw(myshape) or myshape.draw(); But how do i implement best shapes ? You could also do something like: ```d import std; struct Circle { double radius; void draw() { writeln(format!"Draw a circle of radius %s"(radius)); } } struct Rectangle { double width; double height; void draw() { writeln(format!"Draw a rectangle of width %s and height %s."(width,height)); } } alias Shape = SumType!(Circle,Rectangle); void main() { Shape[] shapes = [Shape(Rectangle(2.0,3.)),Shape(Circle(3.0))]; foreach(shape; shapes) { shape.match!(x=>x.draw); } } ``` or ```d import std; struct Circle { double radius; } struct Rectangle { double width; double height; } alias Shape = SumType!(Circle,Rectangle); struct Drawer { int drawerState; void drawShape(Shape shape) { shape.match!(x=>drawShape(x)); } void drawShape(Circle circle) { writeln(format!"Draw a circle of radius %s"(circle.radius)); } void drawShape(Rectangle rectangle) { writeln(format!"Draw a rectangle of width %s and height %s."(rectangle.width,rectangle.height)); } } void main() { Shape[] shapes = [Shape(Rectangle(2.0,3.)),Shape(Circle(3.0))]; Drawer d; foreach(shape; shapes) { d.drawShape(shape); } } ```
Re: What am I doing wrong here?
On Saturday, 7 May 2022 at 02:29:59 UTC, Salih Dincer wrote: On Friday, 6 May 2022 at 18:04:13 UTC, JG wrote: ```d //... struct Adder { int a; int opCall(int b) { return a+b; } } auto adder(int a) { auto ret = Adder.init; ret.a=a; return ret; } void main() { auto g = adder(5); g(5).writeln; // 10 auto d = toDelegate!(int, int)(g); d(5).writeln; // 10 // ... } ``` The value returned by the delegate structure in the above line is 10. Its parameter is 5, but if you do it to 21, you will get 42. So it doesn't have the ability to delegate Adder. In summary, the sum function isn't executing. Instead, its value gets double. SDB@79 What do you mean? ```d import std; struct Delegate(A,B) { B function(void* ptr, A a) f; void* data; B opCall(A a) { return f(data,a); } } auto toDelegate(A, B,S)(ref S s) { static B f(void* ptr, A a) { return (*(cast(S*) ptr))(a); } Delegate!(A,B) ret; ret.f=&f; ret.data= cast(void*) &s; return ret; } struct Adder { int a; int opCall(int b) { return a+b; } } auto adder(int a) { auto ret = Adder.init; ret.a=a; return ret; } void main() { auto g = adder(5); g(5).writeln; auto d = toDelegate!(int, int)(g); d(41).writeln; auto a =7; auto h = (int b)=>a+b; auto d1 = toDelegate!(int,int)(h); void* ptr = cast(void*) &h; (*cast(int delegate(int)*) ptr)(10).writeln; d1(21).writeln; h(32).writeln; } ``` Output: 10 46 17 28 39 Which is what is expected.
Re: What am I doing wrong here?
On Friday, 6 May 2022 at 18:35:40 UTC, Ali Çehreli wrote: On 5/6/22 11:04, JG wrote: > [...] This is a segmentation fault. Reduced: import std; [...] Hi, thanks. That was quite silly. (I was thinking the variable lives to the end of scope of main but not thinking about that I am passing by value).
What am I doing wrong here?
This isn't code to be used for anything (just understanding). ```d import std; struct Delegate(A,B) { B function(void* ptr, A a) f; void* data; B opCall(A a) { return f(data,a); } } auto toDelegate(A, B,S)(S s) { static B f(void* ptr, A a) { return (*(cast(S*) ptr))(a); } Delegate!(A,B) ret; ret.f=&f; ret.data= cast(void*) &s; return ret; } struct Adder { int a; int opCall(int b) { return a+b; } } auto adder(int a) { auto ret = Adder.init; ret.a=a; return ret; } void main() { auto g = adder(5); g(5).writeln; auto d = toDelegate!(int, int)(g); d(5).writeln; auto a =7; auto h = (int b)=>a+b; auto d1 = toDelegate!(int,int)(h); void* ptr = cast(void*) &h; (*cast(int delegate(int)*) ptr)(10).writeln; d1(10).writeln; h(10).writeln; } ```
String Literals
Hi, The specification of string literals has either some errors or I don't understand what is meant by a Character. For instance we have: WysiwygString: r" WysiwygCharacters_opt " StringPostfix_opt WysiwygCharacters: WysiwygCharacter WysiwygCharacter WysiwygCharacters WysiwygCharacter: Character EndOfLine Character: any Unicode character Which to me means that e.g. r""" should be a WysiwygString, which the compiler thinks is not (not surprisingly). Am I misunderstanding something?
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Monday, 2 May 2022 at 19:17:19 UTC, Stanislav Blinov wrote: On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote: Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code: ```d template MyAlias(T){ alias MyAlias = int; } T simp(T)(MyAlias!T val){ return T.init; } int main(){ simp(3);//Impossible to deduce T Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out. Maybe I am being silly, but it isn't possible to determine T here. Independent of what T is the input parameter would be an int (which the compiler can't see but we can) but the output depends on T which can't be deduced.
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote: On Sunday, 1 May 2022 at 03:57:12 UTC, Elfstone wrote: [...] Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code: ```d template MyAlias(T){ alias MyAlias = int; } T simp(T)(MyAlias!T val){ return T.init; } int main(){ simp(3);//Impossible to deduce T simp( cast(MyAlias!string) 4);//Also invalid since MyAlias!string is exactly int simp!string(4);//Ok, no parameter deduction } ``` I don't really see what your example is trying to show. This also doesn't work, and in my mind should be equivalent: ```d T simp(T)(int val) { return T.init; } int main() { simp(3);//Impossible to deduce T } ```
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Sunday, 1 May 2022 at 11:34:49 UTC, JG wrote: On Sunday, 1 May 2022 at 07:59:57 UTC, Elfstone wrote: On Sunday, 1 May 2022 at 06:42:26 UTC, Tejas wrote: [...] Thanks a lot! So this really is a D "feature". The current behaviour is so broken. It makes no sense, for a language user at least. I don't understand why it's not yet solved, if it's a known issue. I guess the current best is something like: ```d enum isVector(V) = is(V==MatrixImpl!(S,1,N),S,size_t N); @nogc auto dot1(V)(in V lhs, in V rhs) if(isVector!V) { return dot2(lhs,rhs); } ``` or ```d enum isVector(V) = is(V==MatrixImpl!(S,1,N),S,size_t N); @nogc auto dot1(V)(in V lhs, in V rhs) if(isVector!V) { static if(is(V==MatrixImpl!(S,1,N),S,N)) { S ret=0; return ret; } static assert("This should never been shown"); } ``` The static assert isn't needed. ```d enum isVector(V) = is(V==MatrixImpl!(S,1,N),S,size_t N); @nogc auto dot1(V)(in V lhs, in V rhs) if(isVector!V) { static if(is(V==MatrixImpl!(S,1,N),S,N)) { S ret=0; return ret; } } ```
Re: Parameters declared as the alias of a template won't accept the arguments of the same type.
On Sunday, 1 May 2022 at 07:59:57 UTC, Elfstone wrote: On Sunday, 1 May 2022 at 06:42:26 UTC, Tejas wrote: On Sunday, 1 May 2022 at 03:57:12 UTC, Elfstone wrote: module test; struct MatrixImpl(S, size_t M, size_t N) { } [...] AFAICT, I'm afraid you'll have to stick to `dot2` 🙁 This DIP I believe does what you want but... It wasn't looked upon favorably... https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1023.md Thanks a lot! So this really is a D "feature". The current behaviour is so broken. It makes no sense, for a language user at least. I don't understand why it's not yet solved, if it's a known issue. I guess the current best is something like: ```d enum isVector(V) = is(V==MatrixImpl!(S,1,N),S,size_t N); @nogc auto dot1(V)(in V lhs, in V rhs) if(isVector!V) { return dot2(lhs,rhs); } ``` or ```d enum isVector(V) = is(V==MatrixImpl!(S,1,N),S,size_t N); @nogc auto dot1(V)(in V lhs, in V rhs) if(isVector!V) { static if(is(V==MatrixImpl!(S,1,N),S,N)) { S ret=0; return ret; } static assert("This should never been shown"); } ```
Re: Reference counting example
On Tuesday, 26 April 2022 at 06:55:34 UTC, Alain De Vos wrote: Can someone provide a simple/very simple reference counting or refcounted example i can understand. Thanks. I suggest to look at RefCounted [here](https://code.dlang.org/packages/automem) rather than in Phobos. There are simple examples.
Re: Understanding alias template parameters
On Thursday, 21 April 2022 at 21:02:47 UTC, JG wrote: Hi, Could someone possibly help me to understand why the commented line doesn't compile? ```d import std; struct MapResult(R,F) { R r; const F f; auto empty() { return r.empty; } auto front() { return f(r.front); } void popFront() { r.popFront; } auto save() { return typeof(this)(r.save,f); } } auto myMap(alias f, R)(R r) { return MapResult!(R,typeof(f))(r,f); } void main() { int function(int) f = x=>2*x; iota(10).myMap!f.writeln; //iota(10).myMap!(x=>2*x).writeln; <--- Why doesn't this compile? } ``` (I do know that Phobos's map works differently with better performance). Thank you to all for the great replies. To fix it one could do: ```d import std; struct MapResult(R,F) { R r; const F f; auto empty() { return r.empty; } auto front() { return f(r.front); } void popFront() { r.popFront; } auto save() { return typeof(this)(r.save,f); } } auto myMap(alias f, R)(R r) { static if(__traits(compiles,f!(typeof(R.init.front { auto fun = f!(typeof(R.init.front)); return MapResult!(R,typeof(fun))(r,fun); } else { return MapResult!(R,typeof(f))(r,f); } } void main() { int function(int) f = x=>2*x; iota(10).myMap!f.writeln; iota(10).myMap!(x=>2*x).writeln; } ``` In response to the change to "alias", which has several upsides including faster code. I would note it also has some downsides including every lambda produces a new type so that (at the moment) the following assert holds: ```d auto r = iota(10).map!(x=>x+1); auto s = iota(10).map!(x=>x+1); assert(!is(typeof(r)==typeof(s))); ```
Understanding alias template parameters
Hi, Could someone possibly help me to understand why the commented line doesn't compile? ```d import std; struct MapResult(R,F) { R r; const F f; auto empty() { return r.empty; } auto front() { return f(r.front); } void popFront() { r.popFront; } auto save() { return typeof(this)(r.save,f); } } auto myMap(alias f, R)(R r) { return MapResult!(R,typeof(f))(r,f); } void main() { int function(int) f = x=>2*x; iota(10).myMap!f.writeln; //iota(10).myMap!(x=>2*x).writeln; <--- Why doesn't this compile? } ``` (I do know that Phobos's map works differently with better performance).
Re: Lambda Tuple with Map Reduce
On Wednesday, 20 April 2022 at 08:04:42 UTC, Salih Dincer wrote: ```d alias type = real; alias func = type function(type a); [...] I think technically you should have save after range in that loop.
Re: RefCounted
On Wednesday, 13 April 2022 at 20:47:33 UTC, JG wrote: Hi, I would have thought that RefCounted!(T, RefCountedAutoInitialize.no) is to be used in place T* when I want reference counting instead of the usual garbage collection (or manual allocation). Perhaps this is wrong? [...] In case some one has a similar problem, try: https://code.dlang.org/packages/automem ``` import std.stdio; import std.experimental.allocator.mallocator; import std.experimental.allocator; import automem; struct Node(T) { RefCounted!(Node!T) next; T val; } struct List(T) { RefCounted!(Node!T) head; bool empty() { return head == null; } T front() { return head.val; } void popFront() { head = head.next; } typeof(this) save() { return typeof(this)(head); } void insert(T x) { head = RefCounted!(Node!T)(head,x); } } void main() { theAllocator = allocatorObject(Mallocator.instance); List!long l; l.insert(5); l.insert(4); l.insert(3); l.insert(2); l.insert(1); writeln(l); } ```
Re: RefCounted
On Wednesday, 13 April 2022 at 20:47:33 UTC, JG wrote: Hi, I would have thought that RefCounted!(T, RefCountedAutoInitialize.no) is to be used in place T* when I want reference counting instead of the usual garbage collection (or manual allocation). Perhaps this is wrong? [...] Perhaps I should have added in case it is relevant, I am not actually interested in building lists. I eventually want to use this in a "persistent" version of a red black tree (where if r is such a tree and we set r1=r.insert(x) then r is unaffected and r1 has the new element inserted - but they share most nodes). This data structure is to be used in a multithreaded application searching for a solution to some problem. The current version has bad performance seemingly due to gc stopping all threads while freeing unused nodes.
RefCounted
Hi, I would have thought that RefCounted!(T, RefCountedAutoInitialize.no) is to be used in place T* when I want reference counting instead of the usual garbage collection (or manual allocation). Perhaps this is wrong? If I am correct what am I doing wrong here? (Sorry for two space squashed style). ``` import std.stdio; import std.typecons; struct Node(T) { RefCounted!(Node!T, RefCountedAutoInitialize.no) next; T val; } struct List(T) { RefCounted!(Node!T, RefCountedAutoInitialize.no) head; bool empty() { return head.refCountedStore.isInitialized; } T front() { return head.val; } void popFront() { head = head.next; } typeof(this) save() { return typeof(this)(head); } } void main() { List!long l; } ``` I also tried my own implementation but that is not working (since not everything is being freed) and probably relies on undefined behavior with my casting away inout, which I did because otherwise the compiler kept giving me errors about not being able to generate a copy constructor for List. ``` import std.stdio; import core.stdc.stdlib; private struct RefCountedPointer(T) { static struct Payload(T) { long cnt=1; T val; } Payload!T* ptr; this(T x) { ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof); *ptr = Payload!T(1,x); } ~this() { if(ptr==null) { return; } (*ptr).cnt--; if((*ptr).cnt == 0) { ptr.val.destroy(); free(ptr); } } @disable this(ref return scope immutable(typeof(this)) rhs); this(ref return scope inout(typeof(this)) rhs) { ptr = cast(Payload!T*) rhs.ptr; if(ptr==null) { return; } ptr.cnt++; } void opAssign(typeof(this) rhs) { if(this.ptr!=null) { (*this.ptr).cnt--; } this.ptr = rhs.ptr; if(this.ptr!=null) { (*this.ptr).cnt++; } } bool isNull() { return ptr==null; } ref auto dref() { assert(!isNull); return (*ptr).val; } } private struct Node(T) { RefCountedPointer!(Node!T) next; T val; } struct List(T) { private RefCountedPointer!(Node!T) head; bool empty() { return head.isNull; } T front() { return head.dref.val; } void popFront() { head = head.dref.next; } auto save() { return typeof(this)(head); } auto insert(T x) { head = RefCountedPointer!(Node!T)(Node!T(head,x)); } } void main() { List!long list; list.insert(8); import std.stdio; import core.stdc.stdlib; private struct RefCountedPointer(T) { static struct Payload(T) { long cnt=1; T val; } Payload!T* ptr; this(T x) { ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof); *ptr = Payload!T(1,x); } ~this() { if(ptr==null) { return; } (*ptr).cnt--; if((*ptr).cnt == 0) { writeln("free"); ptr.val.destroy(); free(ptr); } } @disable this(ref return scope immutable(typeof(this)) rhs); this(ref return scope inout(typeof(this)) rhs) { ptr = cast(Payload!T*) rhs.ptr; if(ptr==null) { return; } ptr.cnt++; } void opAssign(typeof(this) rhs) { "here".writeln; if(this.ptr!=null) { (*this.ptr).cnt--; } this.ptr = rhs.ptr; if(this.ptr!=null) { (*this.ptr).cnt++; } } bool isNull() { return ptr==null; } ref auto dref() { assert(!isNull); return (*ptr).val; } } private struct Node(T) { RefCountedPointer!(Node!T) next; T val; } struct List(T) { private RefCountedPointer!(Node!T) head; bool empty() { return head.isNull; } T front() { return head.dref.val; } void popFront() { head = head.dref.next; } auto save() { return typeof(this)(head); } auto insert(T x) { head = RefCountedPointer!(Node!T)(Node!T(head,x)); } } void main() { List!long list; list.insert(8); import std.stdio; import core.stdc.stdlib; private struct RefCountedPointer(T) { static struct Payload(T) { long cnt=1; T val; } Payload!T* ptr; this(T x) { ptr = cast(Payload!T*) calloc(0,Payload!T.sizeof); *ptr = Payload!T(1,x); } ~this() { if(ptr==null) { return; } (*ptr).cnt--; if((*ptr).cnt == 0) { writeln("free"); ptr.val.destroy(); free(ptr); } } @disable this(ref return scope immutable(typeof(this)) rhs); this(ref return scope inout(typeof(this)) rhs) { ptr = cast(Payload!T*) rhs.ptr; if(ptr==null) { return; } ptr.cnt++; } void opAssign(typeof(this) rhs) { "here".writeln; if(this.ptr!=null) { (*this.ptr).cnt--; } this.ptr = rhs.ptr; if(this.ptr!=null) { (*this.ptr).cnt++; } } bool isNull() { return ptr==null; } ref auto dref() { assert(!isNull); return (*ptr).val; } } private struct Node(T) { RefCountedPointer!(Node!T) next; T val; } struct List(T) { private RefCountedPointer!(Node!T) head; bool empty() { return head.isNull; } T front() { return head.dref.val; } void popFront() { head = head.dref.next; } auto save() { return typeof(this)(head); } auto insert(T x) { head = RefCountedPointer!(Node!T)(Node!T(head,x)); } } void main() { List!long list; list.insert(8); list.
Re: arsd.minigui
On Sunday, 3 April 2022 at 17:10:48 UTC, Adam Ruppe wrote: On Sunday, 3 April 2022 at 16:58:03 UTC, JG wrote: [...] Which resizeImage did you use, from the imageresize module? What pain you have with it? Some of its settings take some tweaking. [...] Thank you very much for your quick reply. I see now I was doing something silly.
arsd.minigui
Hi, I have an png image that I generate (via pdf via pdflatex) that I want to scale and display in a widget. Is this possible via something in arsd? I tried resizeImage but that doesn't seem to do what I expect. Any suggestions?
Variadic templates with default parameters.
Consider the following code: ```d import std; auto logVariadic(T...)(T x,int line=__LINE__,string file=__FILE__) { writeln(file,":",line," ",x); } int variadicCnt; auto logVariadicWrapper(T...)(T x, int line=__LINE__, string file=__FILE__) { variadicCnt++; logVariadic(x,line,file); } auto args(T...)(T x) { static struct Args(T...) { static foreach(i, t; T) { mixin(t, " v",i,";"); } } return Args!T(x); } auto log(Args)(Args args, int line=__LINE__, string file=__FILE__) { writeln(file,":",line," ",args.tupleof); } int cnt; auto logWrapper(Args)(Args args, int line=__LINE__, string file=__FILE__) { cnt++; log(args,line,file); } void main() { logVariadic("Hello ",1234); logVariadicWrapper(1234, " is a number."); //produces wrong line number and adds line number and file name at the end writeln(variadicCnt); log(args("Hello ",1234)); logWrapper(args(1234, " is a number.")); writeln(cnt); } ``` Produces output: onlineapp.d:32 Hello 1234 onlineapp.d:10 1234 is a number.33onlineapp.d 1 onlineapp.d:35 Hello 1234 onlineapp.d:36 1234 is a number. 1 Any other ways to be able to achieve the same without double wrapping arguments like above? I guess the above is okay but I thought I would see other options. (I know that one can pass line and file as template arguments, but that produces a new instance of log or logWrapper per use).
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; [...] You need an order on the elements in a red black tree. Am I correct in thinking you want a container of the form given a key (a string) recover some data (of different types). If so make the elements you store in the red black tree tuples (k,d) where k is a string and d is a variant. Define the order (k1,d1)<(k2,d2) if k1key you get the pair and take the second part. I hope this makes sense.
Re: How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
On Tuesday, 25 January 2022 at 12:27:16 UTC, Dennis wrote: On Tuesday, 25 January 2022 at 12:11:01 UTC, JG wrote: Any ideas how one can achieve what is written in the subject line? ```D void f(T...)(auto ref T args, string file = __FILE__, int line = __LINE__) { writeln(file, ":", line, ": ", args); } ``` Thank you very much.
How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
Any ideas how one can achieve what is written in the subject line? f below does achieve this but I one would expect that it produces significant template bloat. g achieves the aim but isn't very elegant. import std; void f(string file=__FILE__,size_t line=__LINE__,R...)(R r) { writeln(file,":",line," ",r); } void g(T)(T t,string file=__FILE__,size_t line=__LINE__) { writeln(file,":",line," ",t.expand); } void main() { f("hello ", 123); g(tuple("hello ",123)); }
Static indexing
Hi, I want to make a type which has two fields x and y but can also be indexed with [0] and [1] checked at compile time. Is the following reasonable / correct? struct Point { double x; double y; alias expand = typeof(this).tupleof; alias expand this; } unittest { Point p = Point(1.2,3.4); assert(p[0]==1.2); assert(p[1]==3.4); assert(!__traits(compiles,Point.init[3])); }
Re: Printing a quoted string
On Sunday, 2 January 2022 at 17:27:53 UTC, Amit wrote: Hi! I would like to print a string in the same format that I would write it in the code (with quotes and with special characters escaped). Similar to [Go's %q format](https://pkg.go.dev/fmt#hdr-Printing). Is there a safe, built-in way to do that? For example: ``` string s = "one \"two\"\nthree four"; writeln(/* ??? */); ``` And get as output ``` "one \"two\"\nthree four" ``` Instead of ``` one "two" three four ``` Also a bit of a hack. ``` import std.stdio : writeln; import std.format : format; void main() { string s = "one \"two\"\nthree four"; writeln(format("%(%s%)",[s])); } ```
Re: SumType
On Thursday, 28 October 2021 at 13:30:53 UTC, Paul Backus wrote: On Thursday, 28 October 2021 at 09:02:52 UTC, JG wrote: I am heavily using SumType (which I like very much). The problem I am having is that is seems to be causing slow compile times (as can be observed by profiling during the compile). The problem seems to be with match (which is extremely convenient to use). I looked at the code and it does the only reasonable thing too do which is to test each handler against each type. The slow compile time makes development slower and less pleasant, so I am thinking of replacing SumType with my own tagged union and writing out the switches by hand. However, I really don't like this idea since it makes the code less readable and more prone to errors. Any suggestions? Hi, I'm the author of `SumType`. Thanks for bringing this to my attention. The good news is, I have not put a lot of effort so far into micro-optimizing the compile-time performance of `match`, so there is almost certainly room for improvement. If you have an example of the kind of code you are seeing poor compile-time performance for, I'd be happy to use it as a benchmark/profiling target. Any profiling data you've collected would also be helpful. I've created issues for this on Bugzilla and the sumtype Github repository: https://issues.dlang.org/show_bug.cgi?id=22447 https://github.com/pbackus/sumtype/issues/76 Thank you so much for your response (and thanks for the hard work that went into SumType). Here is a rather contrived example which compiles in around 9 seconds on my machine. import std; struct A1 {int val; } struct A2 {int val; } struct A3 {int val; } struct A4 {int val; } struct A5 {int val; } struct A6 {int val; } struct A7 {int val; } struct A8 {int val; } struct A9 {int val; } struct A10 {int val; } struct A11 {int val; } struct A12 {int val; } struct A13 {int val; } struct A14 {int val; } alias A = SumType!(A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13,A14); T asserter(T)() { assert(0); } auto op(A1 x, A1 y, A1 z) { return x.val + y.val + z.val; } auto op(A2 x, A2 y, A2 z) { return x.val + y.val - z.val; } auto op(A3 x, A3 y, A3 z) { return x.val + y.val * z.val; } auto op(A4 x, A4 y, A4 z) { return x.val + y.val & z.val; } auto op(A5 x, A5 y, A5 z) { return x.val - y.val + z.val; } auto op(A6 x, A6 y, A6 z) { return x.val - y.val - z.val; } auto op(A7 x, A7 y, A7 z) { return x.val - y.val * z.val; } auto op(A8 x, A8 y, A8 z) { return x.val - y.val & z.val; } auto op(A9 x, A9 y, A9 z) { return x.val * y.val + z.val; } auto op(A10 x, A10 y, A10 z) { return x.val * y.val - z.val; } auto op(A11 x, A11 y, A11 z) { return x.val * y.val * z.val; } auto op(A12 x, A12 y, A12 z) { return x.val * y.val & z.val; } auto op(A13 x, A13 y, A13 z) { return x.val & y.val + z.val; } auto op(A14 x, A14 y, A14 z) { return x.val & y.val - z.val; } auto op(A a, A b, A c) { return a.match!( x=>b.match!( y=>c.match!(z=>op(x,y,z), _=>asserter!int), _=>asserter!int)); } auto op2(A a, A b, A c) { alias doMatch = match!( (x, y, z) => op(x,y,z), (_1, _2, _3) => asserter!int ); return doMatch(a, b, c); } void main() { A a = A1(12); A b = A1(13); A c = A1(14); assert(op(a,b,c)==39); assert(op2(a,b,c)==39); }
SumType
I am heavily using SumType (which I like very much). The problem I am having is that is seems to be causing slow compile times (as can be observed by profiling during the compile). The problem seems to be with match (which is extremely convenient to use). I looked at the code and it does the only reasonable thing too do which is to test each handler against each type. The slow compile time makes development slower and less pleasant, so I am thinking of replacing SumType with my own tagged union and writing out the switches by hand. However, I really don't like this idea since it makes the code less readable and more prone to errors. Any suggestions?
Re: what's the most efficient way to implement std.container.binaryheap.back()?
On Monday, 25 October 2021 at 04:49:12 UTC, mw wrote: Hi, https://dlang.org/phobos/std_container_binaryheap.html The binary heap induces structure over the underlying store such that accessing the largest element (by using the front property) is a Ο(1) operation. I'm wondering what's the most efficient (in terms of both speed and memory usage) way to implement std.container.binaryheap.back()? i.e accessing the smallest element. Has anyone done this before? Thanks. I didn't look at the implementation, but the implementations I have looked at are backed by an array (a random access container would do). If so you need to find the min of elements from the largest "one less than a power of two" less than the size of the heap up to the size of heap. However, perhaps an alternative data struct would be better? See e.g. https://en.m.wikipedia.org/wiki/Min-max_heap On Monday, 25 October 2021 at 04:49:12 UTC, mw wrote:
Re: Dustmite and linking error
On Saturday, 4 September 2021 at 08:54:31 UTC, Mike Parker wrote: On Saturday, 4 September 2021 at 08:19:53 UTC, JG wrote: [...] You should be able to do that now with "sourceFiles" and "sourcePaths". Just avoid the default "source" or "src" directories and specify the paths and/or files you want for each configuration. I didn't know about this. Thanks you for letting me know.
Re: Dustmite and linking error
On Saturday, 4 September 2021 at 08:05:16 UTC, JG wrote: On Saturday, 4 September 2021 at 07:40:07 UTC, Vladimir Panteleev wrote: On Saturday, 4 September 2021 at 07:38:34 UTC, Andre Pany wrote: The Dustmite condition you are using seems very generic, therefore this error message can be triggered by various code constellations. This might be the reasons why Dustmite is running so long. Overly generic test conditions would be more likely to cause DustMite to finish very quickly (and produce the wrong result), rather than the other way around. In the end I did the reduction by hand and discovered that the problem is that the behaviour of dub changed. It seems to now exclude the mainSourceFile of other configurations in the build (which I guess shouldn't matter) except we had an old configuration which after some renaming had a wrong mainSourceFile which was needed for the build of the configuration in question. Thanks for the suggestions. As a small comment regarding dub. I can't help wondering if it really the best idea for each configuration to include everything by default and then have to exclude things? This means that when you add another configuration and source files for it you very often have to modify all other existing ones. If instead you choose what to include this wouldn't happen. Wild cards support could be added for included files to make projects with a single configuration just as simple as now. Just some thoughts. (I feel the same way regarding gitignore, I would rather have the opposite.)
Re: Dustmite and linking error
On Saturday, 4 September 2021 at 07:40:07 UTC, Vladimir Panteleev wrote: On Saturday, 4 September 2021 at 07:38:34 UTC, Andre Pany wrote: The Dustmite condition you are using seems very generic, therefore this error message can be triggered by various code constellations. This might be the reasons why Dustmite is running so long. Overly generic test conditions would be more likely to cause DustMite to finish very quickly (and produce the wrong result), rather than the other way around. In the end I did the reduction by hand and discovered that the problem is that the behaviour of dub changed. It seems to now exclude the mainSourceFile of other configurations in the build (which I guess shouldn't matter) except we had an old configuration which after some renaming had a wrong mainSourceFile which was needed for the build of the configuration in question. Thanks for the suggestions.
Re: Dustmite and linking error
On Saturday, 4 September 2021 at 06:18:52 UTC, JG wrote: On Friday, 3 September 2021 at 19:56:30 UTC, JG wrote: [...] I tried again. What am I doing wrong? cp source ~/tmp/source cd ~/tmp/source dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status" echo $? #produces 0 find . -name *.o -delete ~/d/DustMite/dustmite -j ./ 'dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status"' cd ../source.reduced dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status" echo $? #produces 1 First line should be: cp -R source ~/tmp/source
Re: Dustmite and linking error
On Friday, 3 September 2021 at 19:56:30 UTC, JG wrote: On Thursday, 2 September 2021 at 17:56:54 UTC, Vladimir Panteleev wrote: On Thursday, 2 September 2021 at 11:20:18 UTC, Vladimir Panteleev wrote: One way to get a very rough estimate is to take the square of the current reduction (.reduced directory), and divide it by the square of the original source. I meant the square of the size of the respective directory. (bytes / LOC / SLOC...) One week later it is still running (depth 22). If you are still on the first iteration, you may also try switching to the "careful" strategy. Thanks for the information. I stopped dustMite and realized I must have done something wrong since the reduced test case doesn't reproduce the problem. I would really like to try and produce a reduced test case of this problem. However having spent three or four hours trying to figure out what I am doing wrong I think I will have to stop at this point. I tried again. What am I doing wrong? cp source ~/tmp/source cd ~/tmp/source dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status" echo $? #produces 0 find . -name *.o -delete ~/d/DustMite/dustmite -j ./ 'dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status"' cd ../source.reduced dub build --config prog1 2>&1 | grep "collect2: error: ld returned 1 exit status" echo $? #produces 1
Re: Dustmite and linking error
On Thursday, 2 September 2021 at 17:56:54 UTC, Vladimir Panteleev wrote: On Thursday, 2 September 2021 at 11:20:18 UTC, Vladimir Panteleev wrote: One way to get a very rough estimate is to take the square of the current reduction (.reduced directory), and divide it by the square of the original source. I meant the square of the size of the respective directory. (bytes / LOC / SLOC...) One week later it is still running (depth 22). If you are still on the first iteration, you may also try switching to the "careful" strategy. Thanks for the information. I stopped dustMite and realized I must have done something wrong since the reduced test case doesn't reproduce the problem. I would really like to try and produce a reduced test case of this problem. However having spent three or four hours trying to figure out what I am doing wrong I think I will have to stop at this point.
Re: Dustmite and linking error
On Thursday, 2 September 2021 at 11:19:55 UTC, jfondren wrote: On Thursday, 2 September 2021 at 11:04:12 UTC, JG wrote: Hi, We hit a linking error (after upgrading to dub 1.26.0). I thought I would try to use dustmite to create a reduced error test case. One week later it is still running (depth 22). I don't suppose there is anyway of determining when it will finish? Possibly it's not a compiler error at all but a name-mangling change combined with some stale objects in your build. Thanks for the suggestion. I thought I was doing this. What I did was run: dub clean --all-packages dub build --force Then I am getting twelve linking errors. Of the form: .. error: undefined reference to .
Dustmite and linking error
Hi, We hit a linking error (after upgrading to dub 1.26.0). I thought I would try to use dustmite to create a reduced error test case. One week later it is still running (depth 22). I don't suppose there is anyway of determining when it will finish?
Re: Profiling
On Tuesday, 24 August 2021 at 09:45:31 UTC, JG wrote: On Tuesday, 24 August 2021 at 09:42:29 UTC, JG wrote: On Tuesday, 24 August 2021 at 09:36:06 UTC, JG wrote: [...] In case anyone is interested it seems that it was forked to here: https://github.com/joakim-brannstrom/profdump Perhaps the dub page could be updated? Tried to continue following the instructions. Ran: profdump -b trace.log trace.log.b Got: core.exception.RangeError@source/app.d(134): Range violation ??:? [0x557458c2bad5] ??:? [0x557458c2d556] ??:? [0x557458c147af] ??:? [0x557458c0b458] ??:? [0x557458c0bb47] app.d:133 [0x557458b96199] ??:? [0x557458c1449b] ??:? [0x557458c14397] ??:? [0x557458c141ed] /home/jg/dlang/ldc-1.26.0/bin/../import/core/internal/entrypoint.d:42 [0x557458b979d4] ??:? __libc_start_main [0x7f0f84d39cb1] ??:? [0x557458b4a0cd] The reason for the crash boils down to the fact that this fails: foreach(k; sort!"a > b"(funcs.keys)) assert(k in funcs); funcs is of type ubyte[4][float] Is this a compiler bug?
Re: Profiling
On Tuesday, 24 August 2021 at 09:42:29 UTC, JG wrote: On Tuesday, 24 August 2021 at 09:36:06 UTC, JG wrote: On Wednesday, 10 February 2021 at 23:42:31 UTC, mw wrote: [...] I tried to do this, but I am not sure how to install profdump. What I did is cloned the repository using git. Tried to build it using dub but got an error as described here: [...] In case anyone is interested it seems that it was forked to here: https://github.com/joakim-brannstrom/profdump Perhaps the dub page could be updated? Tried to continue following the instructions. Ran: profdump -b trace.log trace.log.b Got: core.exception.RangeError@source/app.d(134): Range violation ??:? [0x557458c2bad5] ??:? [0x557458c2d556] ??:? [0x557458c147af] ??:? [0x557458c0b458] ??:? [0x557458c0bb47] app.d:133 [0x557458b96199] ??:? [0x557458c1449b] ??:? [0x557458c14397] ??:? [0x557458c141ed] /home/jg/dlang/ldc-1.26.0/bin/../import/core/internal/entrypoint.d:42 [0x557458b979d4] ??:? __libc_start_main [0x7f0f84d39cb1] ??:? [0x557458b4a0cd]
Re: Profiling
On Tuesday, 24 August 2021 at 09:36:06 UTC, JG wrote: On Wednesday, 10 February 2021 at 23:42:31 UTC, mw wrote: [...] I tried to do this, but I am not sure how to install profdump. What I did is cloned the repository using git. Tried to build it using dub but got an error as described here: [...] In case anyone is interested it seems that it was forked to here: https://github.com/joakim-brannstrom/profdump Perhaps the dub page could be updated?
Re: Profiling
On Wednesday, 10 February 2021 at 23:42:31 UTC, mw wrote: On Wednesday, 10 February 2021 at 11:52:51 UTC, JG wrote: As a follow up question I would like to know what tool people use to profile d programs? I use this one: https://code.dlang.org/packages/profdump e.g. ``` dub build --build=debug --build=profile # run your program to generate trace.log profdump -b trace.log trace.log.b profdump -f --dot --threshold 1 trace.log trace.log.dot echo 'view it with: xdot trace.log.dot' ``` I tried to do this, but I am not sure how to install profdump. What I did is cloned the repository using git. Tried to build it using dub but got an error as described here: https://github.com/AntonMeep/profdump/issues/6 I then modified the dub.json and got it to build but it only produced a library. So I modified the dub.json again to tell it to build an executable and got: core.exception.AssertError@source/app.d(4): TODO ??:? [0x561af7b38025] ??:? [0x561af7b39aa6] ??:? [0x561af7b1cd8f] ??:? [0x561af7b15469] app.d:4 [0x561af7aebc62] ??:? [0x561af7b1ca7b] ??:? [0x561af7b1c977] ??:? [0x561af7b1c7cd] /home/james/dlang/ldc-1.26.0/bin/../import/core/internal/entrypoint.d:42 [0x561af7aebc94] ??:? __libc_start_main [0x7f5ba99accb1] ??:? [0x561af7aeb62d] Program exited with code 1 I then looked inside source/app.d and found: version(unittest) { } else { void main() { assert(0, "TODO"); } } How does one install profdump?
Re: Vibe.d error
On Friday, 20 August 2021 at 10:50:12 UTC, WebFreak001 wrote: On Wednesday, 18 August 2021 at 19:51:00 UTC, JG wrote: [...] There might be incompatibilities with how openssl is used and the installed openssl version or config. If you are getting this from having https enabled on the server, I would recommend instead switching to HTTP-only and using a reverse proxy such as with nginx or caddy to serve it with HTTPS. Thank you very much for your reply. Yes, we are getting this with HTTPS enabled. May I ask why you suggest not to use HTTPS?
Vibe.d error
Hi, We are intermittently getting the following error: Accept TLS connection: server OpenSSL error at ../ssl/record/rec_layer_s3.c:1543: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown (SSL alert number 46) HTTP connection handler has thrown: Accepting SSL tunnel: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown (336151574) Full error: object.Exception@/home/jg/.dub/packages/vibe-d-0.9.3/vibe-d/tls/vibe/stream/openssl.d(578): Accepting SSL tunnel: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown (336151574) Anyone have any idea what might cause this?
Re: Concurrency message passing
On Tuesday, 17 August 2021 at 12:24:14 UTC, Steven Schveighoffer wrote: On 8/17/21 7:05 AM, JG wrote: Hi I have a program with two threads. One thread produces data that is put in a queue and then consumed by the other thread. I initially built a custom queue to do this, but thought this should have some standard solution in D? I looked at std.concurrency and thought that message passing could be used. However, the problem is that I get the following error. Error: static assert: "Aliases to mutable thread-local data not allowed." I am not sure how to solve this. Maybe message parsing isn't the correct solution? Is there some standard solution to this in D? Data with references needs to be marked either immutable or shared in order to be passed using std.concurrency. D is strict about not sharing thread-local data, because then you can use the type system to prove lock-free code is valid. However, data that has no references (aliases) should be passable regardless of mutability, because you are passing a copy. -Steve Thanks for the suggestions and explanations. I am not sure what to do in my case though. The situation is as follows. I have a struct that is populated via user input not necessarily at single instance (so that seems to rule out immutable). On the other hand while it is being populate it is only accessible from one thread so that makes using shared messy. After being populated it should be passed to the other thread and no references are kept. What I am doing currently is populating the struct and casting to shared when I push into a synchronized queue (no references to its data are kept in the first thread). Is what I am doing wrong and can it be achieved using message passing?
Concurrency message passing
Hi I have a program with two threads. One thread produces data that is put in a queue and then consumed by the other thread. I initially built a custom queue to do this, but thought this should have some standard solution in D? I looked at std.concurrency and thought that message passing could be used. However, the problem is that I get the following error. Error: static assert: "Aliases to mutable thread-local data not allowed." I am not sure how to solve this. Maybe message parsing isn't the correct solution? Is there some standard solution to this in D?
Re: Anyway to achieve the following
On Sunday, 15 August 2021 at 21:53:14 UTC, Carl Sturtivant wrote: On Sunday, 15 August 2021 at 07:10:17 UTC, JG wrote: [...] What you are asking for are reference variables. C++ has them: the example here illustrates the behavior you want. https://www.geeksforgeeks.org/references-in-c/ [...] Thanks for the links and code. Looking at the assembly as suggested by others it seems that after optimization this not too bad.
Re: Anyway to achieve the following
On Saturday, 14 August 2021 at 20:50:47 UTC, Carl Sturtivant wrote: ``` struct S { int x = 1234; } void main() { import std.stdio; S s; //construction of a using &(s.x) auto a = Ref!(int)(&s.x); writeln(a); //displays 1234 s.x += 1; writeln(a); //displays 1235 a += 1; writeln(s.x); //displays 1236 } struct Ref(T) { T* ptr; this(T* p) { ptr = p; } string toString() { import std.conv; return to!string(*ptr); } ref T var() { return *ptr; } alias var this; } ``` Hi, This is exactly the behaviour I was trying to obtain. It however comes with a fair amount of overhead, as can be seen in the following llvm ir: define i32 @_Dmain({ i64, { i64, i8* }* } %unnamed) #0 { %s = alloca %onlineapp.S, align 4 ; [#uses = 4, size/byte = 4] %a = alloca %"onlineapp.Ref!int.Ref", align 8 ; [#uses = 5, size/byte = 8] %1 = bitcast %onlineapp.S* %s to i8*; [#uses = 1] call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 %1, i8* align 1 bitcast (%onlineapp.S* @onlineapp.S.__init to i8*), i64 4, i1 false) %2 = bitcast %"onlineapp.Ref!int.Ref"* %a to i8* ; [#uses = 1] call void @llvm.memset.p0i8.i64(i8* align 1 %2, i8 0, i64 8, i1 false) %3 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 1, type = i32*] %4 = call %"onlineapp.Ref!int.Ref"* @pure nothrow ref @nogc @safe onlineapp.Ref!(int).Ref onlineapp.Ref!(int).Ref.__ctor(int*)(%"onlineapp.Ref!int.Ref"* nonnull returned %a, i32* %3) #4 ; [#uses = 0] %5 = load %"onlineapp.Ref!int.Ref", %"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1] call void @@safe void std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %5) #4 %6 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 2, type = i32*] %7 = load i32, i32* %6, align 4 ; [#uses = 1] %8 = add i32 %7, 1 ; [#uses = 1] store i32 %8, i32* %6, align 4 %9 = load %"onlineapp.Ref!int.Ref", %"onlineapp.Ref!int.Ref"* %a, align 8 ; [#uses = 1] call void @@safe void std.stdio.writeln!(onlineapp.Ref!(int).Ref).writeln(onlineapp.Ref!(int).Ref)(%"onlineapp.Ref!int.Ref" %9) #4 %10 = call i32* @pure nothrow ref @nogc @safe int onlineapp.Ref!(int).Ref.var()(%"onlineapp.Ref!int.Ref"* nonnull %a) #4 ; [#uses = 2] %11 = load i32, i32* %10, align 4 ; [#uses = 1] %12 = add i32 %11, 1; [#uses = 1] store i32 %12, i32* %10, align 4 %13 = getelementptr inbounds %onlineapp.S, %onlineapp.S* %s, i32 0, i32 0 ; [#uses = 1, type = i32*] %14 = load i32, i32* %13, align 4 ; [#uses = 1] call void @@safe void std.stdio.writeln!(int).writeln(int)(i32 %14) #4 ret i32 0 }
Re: Anyway to achieve the following
On Friday, 13 August 2021 at 17:19:43 UTC, H. S. Teoh wrote: On Fri, Aug 13, 2021 at 05:11:50PM +, Rekel via Digitalmars-d-learn wrote: [...] For anyone more experienced with C, I'm not well known with references but are those semantically similar to the idea of using a type at a predefined location? References are essentially pointers under the hood. The difference is that at the language level they are treated as aliases to the original variable, and are therefore guaranteed to be non-null. Note that in D `ref` is not a type constructor but a storage qualifier, so you cannot declare a reference variable, you can only get one if you pass a variable to a function that takes it by ref. T Thanks for all the replies. I had a look at emplace but it does not seem to do exactly what I have in mind. What I had in mind would have the following behaviour. Suppose we optionally allow "in before the semi-colon at the end of a declaration. With the following semantics T x; T y in &x; assert(x==y); assert(&x==&y); Note that I am not suggesting that the syntax I wrote is what exists or should exist. I think what I am suggesting is not the same as say implicitly dereferenced pointers. If you think of the underlying machine, variables are aliases for locations in memory where values are stored, and what I am asking is whether it is possible to alias an arbitrary location (provided it contains the correct type.) (I guess what I am saying is only conceptually true variables might end up in registers, but from the point of view of the language it is true since if v is a variable, then &v is defined to be its address.) This would allow things like: Given: struct S { int x; int y; } You can write: S s = S(1,2) in new S; ending up with s being defined on the heap. Anyway I hope it is clearer what I mean. Is it possible to do this in d?
Anyway to achieve the following
Suppose one has a pointer p of type T*. Can on declare variable a of type T which is stored in the location pointed to by p? As an example if we have: struct S { int x = 1234; } void main() { S s; //unknown construction of a using &(s.x) writeln(a); //displays 1234 s.x = s.x+1; writeln(a); //displays 1235 a = a +1; writeln(s.x); //displays 1236 } Similar behavior can be achieved in the body of the lambda here import std.stdio; struct S { int x = 1234; } void main() { S s; (ref a){ writeln(a); s.x = s.x + 1; writeln(a); a = a +1; writeln(s.x); }(s.x); }
Re: Tracy
On Saturday, 7 August 2021 at 14:36:39 UTC, Dennis wrote: On Friday, 6 August 2021 at 12:30:16 UTC, JG wrote: I guess this means that tracy has been integrated? If this is so is it documented anywhere how to use it? Stefan Koch's WIP tracy integration in DMD is completely separate from Johan Engelen's time tracing added to LDC in 1.25.0. Note that the latter is not specific to tracy, I just recommended using tracy to view the trace file because alternatives I tried (Google Chrome and Speedscope) are terribly slow, see: https://forum.dlang.org/post/phuwlvsjigbyfvslk...@forum.dlang.org I'm not aware of any documentation of the feature. Thanks, a lot.
Tracy
There was a message a while back (https://forum.dlang.org/post/fyakhpjbcpzqegfev...@forum.dlang.org) about adding support for tracy. When I asked a question about compile time performance I received the following instructions: https://forum.dlang.org/post/eevoyuwhbuycyzgxs...@forum.dlang.org I guess this means that tracy has been integrated? If this is so is it documented anywhere how to use it?
Re: Passing delegate indirectly to createLowLevelThread doesn't work
On Monday, 26 July 2021 at 16:46:40 UTC, Tejas wrote: On Monday, 26 July 2021 at 15:42:44 UTC, Paul Backus wrote: On Monday, 26 July 2021 at 15:29:26 UTC, Tejas wrote: ```d import std; import core.thread.osthread; void delegate() f; void main() { void func(){} f = &func; createLowLevelThread(&func, 2<<30);//works createLowLevelThread(f, 2<<30);// doesn't work!! } ``` Can someone help? The delegate must be `nothrow`: ```d void delegate() nothrow f; ``` Doesn't seem to matter. I tried that beforehand. And even if it did why does passing it directly work without explicitly qualifying it as nothrow then? It does work for me. To me running the following explains why: ```d import std; import core.thread.osthread; void delegate() f; void main() { void func(){} f = &func; pragma(msg,typeof(&func)); pragma(msg,typeof(f)); createLowLevelThread(&func, 2<<30);//works //createLowLevelThread(f, 2<<30);// doesn't work!! } ```
Re: How to check if variable of some type can be of null value?
On Saturday, 24 July 2021 at 20:10:37 UTC, JG wrote: On Saturday, 24 July 2021 at 19:39:02 UTC, Alexey wrote: [...] There are probably better ways. However, this seems to work: ```d import std; enum canBeSetToNull(T) = __traits(compiles,(T.init is null)); interface I1 { } class C1 : I1 { } struct S1 { } struct S2 { int a=1; } void main() { auto c1 = new C1; I1 i1 = c1; auto s1 = S1(); auto s2 = S2(); static assert(canBeSetToNull!(typeof(c1))); static assert(canBeSetToNull!(typeof(i1))); static assert(!canBeSetToNull!(typeof(s1))); static assert(!canBeSetToNull!(typeof(s2))); static assert(!canBeSetToNull!(int)); static assert(canBeSetToNull!(int*)); }``` Sorry, I see that is basically what you had.
Re: How to check if variable of some type can be of null value?
On Saturday, 24 July 2021 at 19:39:02 UTC, Alexey wrote: On Saturday, 24 July 2021 at 18:10:07 UTC, Alexey wrote: I've tried to use ```typeof(t) is cast(t)null```, but compiler exits with error and so this can't be used for checking this issue. The goal I with to achieve by this check - is to use template and to assign value to variable basing on it's ability to accept null as a value. currently I ended up using ```__traits(compiles, cast(T1)null)``` for this check. but don't know is this really semantically correct. There are probably better ways. However, this seems to work: ```d import std; enum canBeSetToNull(T) = __traits(compiles,(T.init is null)); interface I1 { } class C1 : I1 { } struct S1 { } struct S2 { int a=1; } void main() { auto c1 = new C1; I1 i1 = c1; auto s1 = S1(); auto s2 = S2(); static assert(canBeSetToNull!(typeof(c1))); static assert(canBeSetToNull!(typeof(i1))); static assert(!canBeSetToNull!(typeof(s1))); static assert(!canBeSetToNull!(typeof(s2))); static assert(!canBeSetToNull!(int)); static assert(canBeSetToNull!(int*)); }```
Re: Build time
On Saturday, 24 July 2021 at 09:12:15 UTC, JG wrote: On Saturday, 24 July 2021 at 08:26:39 UTC, JG wrote: On Friday, 23 July 2021 at 20:03:22 UTC, Dennis wrote: [...] Thanks for this suggestion. Unfortunately this makes the compile use too much memory for my system and so it gets killed before the end and no my-trace.tracy file is produced. I will try building on parts of the program with this and see if I can see what is going on. Got this to work after removing part of the program, the slowest parts are in library code (sumtype match to be precise). I will look into whether my usage can be improved. I should also mention that what I said about compile time was a little inaccurate, some of that time linking (which involves llvm). Thanks very much to everyone for the help. With a few minor changes so far I have halved the compile time.
Re: Build time
On Saturday, 24 July 2021 at 08:26:39 UTC, JG wrote: On Friday, 23 July 2021 at 20:03:22 UTC, Dennis wrote: On Friday, 23 July 2021 at 18:53:06 UTC, JG wrote: [...] You can try profiling it with LDC 1.25 or later. Add this to dub.sdl: [...] Thanks for this suggestion. Unfortunately this makes the compile use too much memory for my system and so it gets killed before the end and no my-trace.tracy file is produced. I will try building on parts of the program with this and see if I can see what is going on. Got this to work after removing part of the program, the slowest parts are in library code (sumtype match to be precise). I will look into whether my usage can be improved. I should also mention that what I said about compile time was a little inaccurate, some of that time linking (which involves llvm).
Re: Build time
On Friday, 23 July 2021 at 20:03:22 UTC, Dennis wrote: On Friday, 23 July 2021 at 18:53:06 UTC, JG wrote: [...] You can try profiling it with LDC 1.25 or later. Add this to dub.sdl: [...] Thanks for this suggestion. Unfortunately this makes the compile use too much memory for my system and so it gets killed before the end and no my-trace.tracy file is produced. I will try building on parts of the program with this and see if I can see what is going on.
Re: Build time
On Friday, 23 July 2021 at 18:57:46 UTC, Adam D Ruppe wrote: On Friday, 23 July 2021 at 18:53:06 UTC, JG wrote: The program I writing is around 3000 loc what's the code? I am not sure how relevant it is but it is a compiler that I have been writing, not something serious (yet - if ever).
Build time
Hi, The program I writing is around 3000 loc and recently I noticed a large slow down in compile time which after investigation seemed to be caused by my computer running out of memory. The compile was using more than 15GB memory. I tried using lowmem and that did solve the memory problem but the compile still takes around 1 minute. Any suggestion on how to try and improve the build time. I am currently using dub. Of course one could try to use fewer templates and less meta programming but that seems to defeat the purpose of using d.
Documentation
What is the relationship between https://dlang.org/library/ and https://dlang.org/phobos/index.html
Sumtype warning
I am getting the following message: Warning: struct SumType has method toHash, however it cannot be called with const(SumType!(A,B,C)) this Could someone point in the right direction to understand what I am doing that causes this?
Re: Vibe.d diet templates
On Thursday, 17 June 2021 at 18:54:41 UTC, WebFreak001 wrote: On Thursday, 17 June 2021 at 16:26:57 UTC, JG wrote: [...] Thanks, this works. I would have thought this would be a common enough use case to have support in diet. Anyone else wanted this? Opened an issue here: https://github.com/rejectedsoftware/diet-ng/issues/91 Thanks for opening that issue.
Re: Vibe.d diet templates
On Thursday, 17 June 2021 at 09:16:56 UTC, WebFreak001 wrote: On Thursday, 17 June 2021 at 08:23:54 UTC, JG wrote: Suppose I have an array of attributes and values v is there any way to apply these attributes to a tag? So that something like tag(#{v[0]0]}=#{v[0][1]},...}) becomes where v[0][0]="attribute0" and v[0][1]="value0"? I think there is nothing for this built-in in diet, so you have to manually emit raw HTML: ```diet - import std.xml : encode; - auto start = appender!string; - start ~= " Thanks, this works. I would have thought this would be a common enough use case to have support in diet. Anyone else wanted this?
Vibe.d diet templates
Suppose I have an array of attributes and values v is there any way to apply these attributes to a tag? So that something like tag(#{v[0]0]}=#{v[0][1]},...}) becomes where v[0][0]="attribute0" and v[0][1]="value0"?
Two interpretations
Is it specified somewhere which way the following program will be interpreted? import std; struct A { int x=17; } int x(A a) { return 100*a.x; } void main() { A a; writeln(a.x); }
Shift operator, unexpected result
I found the following behaviour, as part of a more complicated algorithm, unexpected. The program: import std; void main() { int n = 64; writeln(123uL>>n); } produces: 123 I would expect 0. What is the rationale for this behaviour or is it a bug?
Re: Understanding RefCounted
On Thursday, 13 May 2021 at 00:53:50 UTC, Steven Schveighoffer wrote: On 5/12/21 1:16 PM, JG wrote: [...] Ah, ok. So reference counting provides a single thing you can point at and pass around without worrying about memory cleanup. But only as long as you refer to it strictly through a RefCounted struct. If you keep a pointer to something in the payload that isn't wrapped in a RefCounted struct (and specifically the original RefCounted struct), then it's possible the RefCounted struct will free the memory while you still hold a reference. [...] Thank you. I was just wondering if something like what you wrote could be achieved using the range above accidentally.
Re: Issue with small floating point numbers
On Thursday, 13 May 2021 at 03:48:49 UTC, Tim wrote: On Thursday, 13 May 2021 at 03:46:28 UTC, Alain De Vos wrote: Not is is not wrong it is wright. Because you use not pi but an approximation of pi the result is not zero but an approximation of zero. Oh, of course. Jesus that sucks big time. Any idea on how to use assert with an approximate number like this? You could try and use this [this](https://dlang.org/library/std/math/is_close.html)
Re: How to use dub with our own package
On Wednesday, 12 May 2021 at 13:37:26 UTC, Vinod K Chandran wrote: Hi all, I am creating a hobby project related with win api gui functions. i would like to work with dub. But How do I use dub in my project. 1. All my gui library modules are located in a folder named "winglib". 2. And that folder also conatains a d file called "package.d" 3. "package.d" contains all the public imports. 4. Outside this winglib folder, I have my main file called "app.d" 5. "app.d" imports "winglib". So in this setup, how do I use dub ? Thanks in advance. Have a look at [link](https://forum.dlang.org/post/jyxdcotuqhcdfqwwh...@forum.dlang.org).
Re: Understanding RefCounted
On Wednesday, 12 May 2021 at 13:38:10 UTC, Steven Schveighoffer wrote: On 5/12/21 3:28 AM, JG wrote: Reading the documentation on RefCounted I get the impression that the following can lead to memory errors. Could someone explain exactly how that could happen? I suppose that problem would be the call something to do with front? ``` private struct RefCountedRangeReturnType(R) { import std.typecons : RefCounted; private RefCounted!R r; auto empty() { return r.refCountedPayload.empty; } auto front() { return r.refCountedPayload.front; } void popFront() { r.refCountedPayload.popFront; } auto save() { return typeof(this)(RefCounted!R(r.refCountedPayload.save)); } } auto refCountedRange(R)(R r) { import std.typecons : RefCounted; return RefCountedRangeReturnType!R(RefCounted!R(r)); } ``` You don't need to access refCountedPayload. RefCounted is supposed to be like a transparent reference type, and should forward all calls to the referenced item. I don't see how you will get memory errors from your code. Maybe you can elaborate why you think that is? -Steve To be honest I can't see the problem. But the following from the documentation made me wonder if I was doing something that could lead to memory problems: "RefCounted is unsafe and should be used with care. No references to the payload should be escaped outside the RefCounted object." In particular I wondered if in some special case holding a reference to front might cause a problem, but perhaps that is incorrect.
Understanding RefCounted
Reading the documentation on RefCounted I get the impression that the following can lead to memory errors. Could someone explain exactly how that could happen? I suppose that problem would be the call something to do with front? ``` private struct RefCountedRangeReturnType(R) { import std.typecons : RefCounted; private RefCounted!R r; auto empty() { return r.refCountedPayload.empty; } auto front() { return r.refCountedPayload.front; } void popFront() { r.refCountedPayload.popFront; } auto save() { return typeof(this)(RefCounted!R(r.refCountedPayload.save)); } } auto refCountedRange(R)(R r) { import std.typecons : RefCounted; return RefCountedRangeReturnType!R(RefCounted!R(r)); } ```
Re: moveToGC
On Monday, 10 May 2021 at 11:11:06 UTC, Mike Parker wrote: On Monday, 10 May 2021 at 10:56:35 UTC, JG wrote: The following compiles with dmd but not with ldc on run.dlang.io. Am I doing something wrong? Please provide the error message(s) when asking questions like this. In this case: ``` onlineapp.d(15): Error: undefined identifier moveToGC onlineapp.d(20): Error: undefined identifier moveToGC ``` Looks like moveToGC was added in 2.096: https://github.com/dlang/druntime/commit/bf59d2dcc4eae068a37db169977eef3eb394cee6 Adding --version to the ldc command line at run.dlang.io shows it's running ldc 1.25.1, which is current with D 2.095.1. Thank you.