Re: can not find the error: Error: TypeInfo cannot be used with -betterC
On Wednesday, 17 July 2019 at 15:52:39 UTC, Newbie2019 wrote: when build my project with -betterC, it throw this error: Error: TypeInfo cannot be used with -betterC There is no location information about it, how can I find what code cause this ? You usually get that *extrememly* unhelpful error message when you use anything that uses TypeInfo. So it can be quite hard to figure out. Did it start happening after you added a class or did something with exceptions? At least those would cause that error.
segfault in ldc release only - looks like some kind of optimization bug?
Hi, so I had this weird bug that was driving me crazy and only segfaulted with ldc in release build - (I'm using ldc 1.16.0). This is the code that segfaults. All parts seem to be necessary for it to happen, or at least I think so. I've gone in circles minimizing so I've probably missed something. But this seems to be it: import std; struct W(T) { T value; ref inout(T) front() inout { return value; } } auto ref get(T)(W!T value) { return value.front; } struct S { string a; } void main() { S[string] aa; aa = ["one" : S("a")]; auto b = W!S(aa["one"]).get; writeln(b); } Running with ldc and -O3 crashes: "ldc2 -O3 -run source.d" Some things I've noticed: - if you remove the call to .get and use .value directly, the crash goes - if you remove the inout specifier on front(), the crash goes - if you remove the ref specifier on front(), the crash goes - if you don't call writeln(b), the crash goes - if you don't use the s returned by the aa, the crash goes - if you *add* a return qualifier on the "front" function, the crash goes away (what is that return thing btw and when do you use it?) Any ideas?
Re: segfault in ldc release only - looks like some kind of optimization bug?
On Tuesday, 23 July 2019 at 00:36:49 UTC, Exil wrote: auto ref get(T)(W!T value) { return value.front; } You're returning a reference to a temporary that gets deleted at the end of the function's scope. The "auto ref" here will be a "ref". . oh ... shit you're right. Ok so this was minimized from this: const config = Config.ghApp(ghDomain) .orElseThrow!(() => new Exception( "could not find config for domain '%s'".format(ghDomain) )); Where Config.ghApp return an Optional!GhApp, and orElseThrow checks if a range has is not empty and returns front. The front in Optional is defined as the front above... So is that an incorrect idiom to use when writing a library then? I pretty sure I've seen it in phobos too. Slapping return on the function also fixes it. Is that the correct way to write a .front? Thanks!
dip1000, perhaps annotate with return, and vibe-d
Trying to get dip1000 flag in use. I have this error: Error: returning Optional(null, false).this(value) escapes a reference to parameter value, perhaps annotate with return in this function: public auto some(T)(auto ref T value) { return Optional!T(value); // <-- error on this line } And it's instantiated from here: static Optional!T fromRepresentation(Json value) { if (value == Json.undefined) { return no!T; } return some(deserializeJson!T(value)); // <-- instantiated from here } I put the qualifier "return" on the parameter to some, but did nothing. And I put it on Optional.this() as well, but I'm not sure where I'm supposed to put it. The constructor for Optional takes an auto ref T ... I'm not sure that makes sense. Does it make sense to take a constructor parameter that is copied in to the struct by auto ref if you're not calling .move on it explicitly? And as for vibe-d, I get this when compiling with dip1000: Also, vibe-d gives me this: ../../../.dub/packages/vibe-core-1.6.2/vibe-core/source/vibe/internal/traits.d(391,2): Error: static assert: "FileStream does not implement method "read" of type @safe ulong(scope ubyte[] dst, IOMode mode)" Has anyone seen that or used vibed with dip1000?
Re: dip1000, perhaps annotate with return, and vibe-d
On Wednesday, 24 July 2019 at 16:23:48 UTC, Paul Backus wrote: On Wednesday, 24 July 2019 at 12:54:51 UTC, aliak wrote: [...] It should go on the constructor's parameter; i.e., this(auto return ref T value) { /* ... */ } Under the hood, a constructor actually returns the constructed value by reference, so the actual signature of the above constructor seen by the lifetime checker is: ref Optional!T __ctor(auto return ref T value) You can see this for yourself with something like `pragma(msg, typeof(Optional!T.__ctor))`. Thanks! The under the hood stuff was good to know! I was putting it in the right place but it seems to still have been complaining. Ah well. I guess an auto ref on a constructor doesn't really make sense anyway.
Any way to move in @disabled this(this) type in to a wrapping template?
Basically, can template W be made to handle an S that can't be copied? import std; static struct S { int i; @disable this(this); this(int i) { this.i = i; } } struct W(T) { T value; this(T value) { this.value = value; } } auto wrap(T)(T value) { return W!T(value); } void main() { auto a = wrap(S(3)); } I tried doing something like: W!T construct(Args...)(auto ref Args args) { import std.algorithm: move; auto value = T(args); W!T w; w.value = move(value); return move(opt); }
Re: Any way to move in @disabled this(this) type in to a wrapping template?
On Thursday, 25 July 2019 at 19:35:36 UTC, aliak wrote: Basically, can template W be made to handle an S that can't be copied? import std; static struct S { int i; @disable this(this); this(int i) { this.i = i; } } struct W(T) { T value; this(T value) { this.value = value; } } auto wrap(T)(T value) { return W!T(value); } void main() { auto a = wrap(S(3)); } I tried doing something like: W!T construct(Args...)(auto ref Args args) { import std.algorithm: move; auto value = T(args); W!T w; w.value = move(value); return move(opt); } So this works - are there any problems with it? struct W(T) { T value; this(T value) { static if (isMutable!T) this.value = value.move; else this.value = value; } } auto wrap(T)(T value) { static if (isMutable!T) return W!T(value.move); else return W!T(value); } Shouldn't this be happening by default? When would you not want that to happen?
Re: Any way to move in @disabled this(this) type in to a wrapping template?
On Thursday, 25 July 2019 at 21:23:33 UTC, Paul Backus wrote: On Thursday, 25 July 2019 at 20:38:59 UTC, aliak wrote: On Thursday, 25 July 2019 at 19:35:36 UTC, aliak wrote: Basically, can template W be made to handle an S that can't be copied? import std; static struct S { int i; @disable this(this); this(int i) { this.i = i; } } [...] So this works - are there any problems with it? struct W(T) { T value; this(T value) { static if (isMutable!T) this.value = value.move; else this.value = value; } } auto wrap(T)(T value) { static if (isMutable!T) return W!T(value.move); else return W!T(value); } Shouldn't this be happening by default? When would you not want that to happen? The way I handle this is with `auto ref` and `core.lifetime.forward`: import core.lifetime: forward; struct W(T) { T value; this()(auto ref T value) { this.value = forward!value; } } auto wrap(T)(auto ref T value) { return W!T(forward!value); } @safe unittest { static struct NoCopy { @disable this(this); } assert(__traits(compiles, { auto test = wrap(NoCopy()); })); assert(!__traits(compiles, { auto lval = NoCopy(); auto test = lval; })); } Interactive: https://run.dlang.io/is/kDJyYC It's not very well documented, but `forward` does essentially the same thing as your `static if` + `move` combination. Note that with both your version and mine, you will run into the same problem I did of `move` making it impossible to use instances of `W` in static initializers and CTFE. [1] The best compromise I was able to come up with was to only call move if `isCopyable!T == false`, which doesn't really solve the problem, but at least contains it. [1] https://github.com/pbackus/sumtype/issues/22 Haha. Ironic. Thanks, again :) Though, if you use auto ref, and you check if it's mutable and not copyable and then move, then that means you could potentially be applying move to an object on behalf of the clients auto a = MyUnmovableType() auto b = LibraryType(a); writeln(a); // ?? If this is a problem, I guess a __traits(isRef, parameter) check along with mutable and copyable could help. Then if client want it moved they could call move explicitly.
Re: cannot use local __lambda1 as parameter to non-global template
On Friday, 26 July 2019 at 16:20:10 UTC, aliak wrote: Can someone help me understand the details around why this fails? import std; struct W(T) { T value; auto hook(handlers...)() { return handlers[0](value); } } template f(handlers...) { auto ref f(T)(auto ref T value) { return value.hook!handlers; } } @nogc void main() { auto a = W!int(3); auto b = a.f!((_) => "yes"); } If I specifically type the lambda I pass in to f (i.e. (int _) => "yes") then it works. Or if I make hook a global template that takes a W!T as the first parameter it also works. Is there a work around for this? Err sorry, that was ldc pre the 5710 bug fix. In DMD I get this: Error: @nogc function D main cannot call non-@nogc function onlineapp.main.f!(W!int).f I guess it's allocating a delegate somewhere. Can I fix that?
Re: cannot use local __lambda1 as parameter to non-global template
On Friday, 26 July 2019 at 16:21:52 UTC, aliak wrote: On Friday, 26 July 2019 at 16:20:10 UTC, aliak wrote: Can someone help me understand the details around why this fails? import std; struct W(T) { T value; auto hook(handlers...)() { return handlers[0](value); } } template f(handlers...) { auto ref f(T)(auto ref T value) { return value.hook!handlers; } } @nogc void main() { auto a = W!int(3); auto b = a.f!((_) => "yes"); } If I specifically type the lambda I pass in to f (i.e. (int _) => "yes") then it works. Or if I make hook a global template that takes a W!T as the first parameter it also works. Is there a work around for this? Err sorry, that was ldc pre the 5710 bug fix. In DMD I get this: Error: @nogc function D main cannot call non-@nogc function onlineapp.main.f!(W!int).f I guess it's allocating a delegate somewhere. Can I fix that? I can do this but ugh: import std; struct W(T) { T value; static auto hook(handlers...)(auto ref typeof(this) self) { return handlers[0](self.value); } } template f(handlers...) { auto ref f(T)(auto ref T value) { return value.hook!handlers(value); } } @nogc void main() { auto a = W!int(3); auto b = a.f!((_) => "yes"); }
cannot use local __lambda1 as parameter to non-global template
Can someone help me understand the details around why this fails? import std; struct W(T) { T value; auto hook(handlers...)() { return handlers[0](value); } } template f(handlers...) { auto ref f(T)(auto ref T value) { return value.hook!handlers; } } @nogc void main() { auto a = W!int(3); auto b = a.f!((_) => "yes"); } If I specifically type the lambda I pass in to f (i.e. (int _) => "yes") then it works. Or if I make hook a global template that takes a W!T as the first parameter it also works. Is there a work around for this?
Re: Passing nested template function
On Saturday, 10 August 2019 at 17:45:43 UTC, Prateek Nayak wrote: A nested function can be passed to another function evident from this example: https://run.dlang.io/is/6waRkB However if the nested function is a template function, it raises an error https://run.dlang.io/is/PQhkwl The error being: cannot get frame pointer to the nested function Is there a way to pass a nested template function to a function declared outside the outer function scope? This looks like it could be a bug to me. If you explicitly instantiate the nested template and call dispatch like dispatch!(nested!0) then it works. An alias template parameter can accept both a template and an instantiated template. I.e. template X(T) {} alias A = X; // ok alias B = X!int; // ok So it's unclear what should happen. At the least, the defaulted argument should be applied at the call site (Func(a)). Note though that neither versions will work on ldc or gdc however. Because there's a bug [0] that has only been fixed in for dmd. [0] https://github.com/dlang/dmd/pull/9282
advise about safety of using move in an opAssign with __traits(isRef
Hi, I'm trying to fix a use-case where you have a wrapper template type (it's an optional) and the wrapping type has @disable this(this). And having this scenario work: struct S { @disable this(this); } Optional!S fun() {...} Optional!S a; a = fun.move; Now that won't work because of the disabled copy, but you can either: 1) Add an explicit move function in the Optional type: struct Optional { auto move(ref Optional!T target) { import std.algorithm: move; return move(this, target); } } Then you could do: fun.move(field); First of all I find the readability confusing, so there's no way to know if fun is moving in to field or field is moving in to fun. But OTOH it matches the phobos move(T src, T target). So conventionally maybe ok. Also it's explicit, so it makes it clear at the call site that a move is happening. 2) use isRef inside opAssign like this: void opAssign(auto ref Optional!T lhs) { static if (__traits(isRef, lhs)) { this._value = lhs._value; } else { import std.algorithm: move; move(lhs._value, this._value); } } Then you could just do: field = fun And it'll just work since fun returns an rvalue. The second solution it seems like it'll just work correctly with the static if guard. But I'm not sure if there're any gotchas I should be aware of? Any advice?
Re: advise about safety of using move in an opAssign with __traits(isRef
On Friday, 16 August 2019 at 14:29:26 UTC, Paul Backus wrote: On Friday, 16 August 2019 at 08:07:28 UTC, aliak wrote: [...] Even simpler: void opAssign(auto ref Optional!T rhs) { import core.lifetime: forward; this._value = forward!rhs; } That doesn't work with private members unfortunately :( - i.e. this.value = forward!(rhs._value) - member inaccessible. Is there a known workaround for that? If not then should I just copy the implementation in place to be correct?
Re: advise about safety of using move in an opAssign with __traits(isRef
On Saturday, 17 August 2019 at 16:43:51 UTC, Paul Backus wrote: On Friday, 16 August 2019 at 08:07:28 UTC, aliak wrote: Hi, I'm trying to fix a use-case where you have a wrapper template type (it's an optional) and the wrapping type has @disable this(this). And having this scenario work: struct S { @disable this(this); } Optional!S fun() {...} Optional!S a; a = fun.move; Now that won't work because of the disabled copy Are you sure? I tried to reproduce the error you're describing, and I couldn't do it. The following compiles and runs without any issues: struct Wrapper(T) { T value; } struct NoCopy { @disable this(this); } Wrapper!NoCopy fun() { return Wrapper!NoCopy(); } void main() { Wrapper!NoCopy a; a = fun(); // already an rvalue, so moved implicitly } Can you give a more complete example of the problem you're having? You'll get the error if you define an opAssign: struct Wrapper(T) { T value; void opAssign(U : T)(Wrapper!U other) { this.value = other.value; } } struct S { @disable this(this); } Wrapper!S fun() { return Wrapper!S(S()); } void main() { Wrapper!S a; a = fun; }
deep copying a struct
Are there any library APIs that allow this: struct S { int[] arr; } void main() { const a = S([1,2,3]); S b = a.copy; // deep dup/copy } I'd also like to avoid implementing a copy constructor for each type.
Re: deep copying a struct
On Friday, 6 September 2019 at 10:37:16 UTC, aliak wrote: Are there any library APIs that allow this: I just put this together. Any holes other the AA related ones? Will it work with classes? auto dupDeep(T)(ref T thing) { import std.range: ElementType; import std.traits: hasAliasing, Unqual, isArray; static if (isArray!T) { Unqual!(ElementType!T)[] copy; foreach (elem; thing) { copy ~= elem.dupDeep; } } else static if (hasAliasing!T) { Unqual!T copy; foreach (i, field; thing.tupleof) { copy.tupleof[i] = field.dupDeep; } } else { Unqual!T copy; copy = thing; } return copy; }
Spawning a process, then killing it on SIGINT
Is there a way to go about killing a process after spawning it on a SIGINT? I can't do this for e.g. because kill is not @nogc. Pid currentSpawnedPid; extern(C) void killCurrentPidHandler(int sig) nothrow @nogc @system { kill(currentSpawnedPid, sig); } int main() { currentSpawnedPid = spawnProcess(["docker-compose", "up"], stdin, stdout, stderr); signal(SIGINT, &killCurrentPidHandler); return wait(currentSpawnedPid); } Any other ways to go about this? Cheers, - Ali
Re: Spawning a process, then killing it on SIGINT
On Saturday, 23 November 2019 at 10:09:51 UTC, mipri wrote: On Saturday, 23 November 2019 at 09:54:48 UTC, aliak wrote: Is there a way to go about killing a process after spawning it on a SIGINT? I can't do this for e.g. because kill is not @nogc. Well, this works: import std; import core.stdc.signal; extern(C) int kill(int pid, int sig) nothrow @nogc @system; int currentSpawnedPid; extern(C) void killCurrentPidHandler(int sig) nothrow @nogc @system { if (currentSpawnedPid > 1) kill(currentSpawnedPid, sig); } int main() { auto pid = spawnProcess(["sleep", "50s"], stdin, stdout, stderr); currentSpawnedPid = pid.processID; signal(SIGINT, &killCurrentPidHandler); return wait(pid); } Thanks, looks like I'll have to go that route.
Re: Spawning a process, then killing it on SIGINT
On Saturday, 23 November 2019 at 12:19:27 UTC, Steven Schveighoffer wrote: On 11/23/19 4:54 AM, aliak wrote: Is there a way to go about killing a process after spawning it on a SIGINT? I can't do this for e.g. because kill is not @nogc. Pid currentSpawnedPid; extern(C) void killCurrentPidHandler(int sig) nothrow @nogc @system { kill(currentSpawnedPid, sig); } int main() { currentSpawnedPid = spawnProcess(["docker-compose", "up"], stdin, stdout, stderr); signal(SIGINT, &killCurrentPidHandler); return wait(currentSpawnedPid); } Any other ways to go about this? Yeah, fix phobos. kill should be @nogc/nothrow, and probably @safe. -Steve Looked in to it, seems step one is getting phobos compiling with dip1008 :/ Kill uses enforce.
How to wait for a shell process to finish on ctrl+c before exiting?
I'm writing some command line tooling stuff, and one of the command spins up a docker compose file (which in short, spins up some services and aggregates the output of each service to stdout). When a user presses ctrl+c, i would like to pass on the ctrl+c to the spawned process and wait till it handles ctrl+c and then let go of the current process. So far I have this: int spawnedPid; extern(C) int kill(int pid, int sig) nothrow @nogc @system; extern(C) void interruptHandler(int sig) nothrow @nogc @system { kill(spawnedPid, sig); } int spawnProcessAndWait(string[] cmd) { auto pid = spawnProcess(cmd, stdin, stdout, stderr); spawnedPid = pid.processID; signal(SIGINT, &interruptHandler); int result = wait(pid); return wait(pid); } It doesn't work. I think the call to kill doesn't wait? Is there a way to make it wait? I can't call kill(Pid) or wait(Pid) inside the interrupt handler because those are not @nogc [0]. [0]: https://forum.dlang.org/thread/mtikzznfaahiltguv...@forum.dlang.org
Re: How to wait for a shell process to finish on ctrl+c before exiting?
On Sunday, 24 November 2019 at 16:05:14 UTC, mipri wrote: On Sunday, 24 November 2019 at 15:44:00 UTC, aliak wrote: [...] This might be useful: --- #! /usr/bin/env rdmd import std; import core.stdc.signal; [...] waitpid, of course! Thanks agin :)
Re: How to wait for a shell process to finish on ctrl+c before exiting?
On Sunday, 24 November 2019 at 17:04:49 UTC, Steven Schveighoffer wrote: On 11/24/19 10:44 AM, aliak wrote: [...] Hm.. are you sure that ctrl-c isn't also sending the signal to your child process? I thought it did. -Steve Yesh, you're right. That extra kill is unnecessary and was actually causing problems. So thanks for that!
Re: Referance usage in async function
On Saturday, 30 November 2019 at 13:45:00 UTC, kerdemdemir wrote: I have simplified my problem which can be seen below. import std.stdio; import vibe.core.core; import vibe.core.concurrency; import vibe.data.json; void main() { int[] list; bool ListManipulator(ref int[] list) { list ~= 2; list ~= 4; return true; } bool ListManipulatorPointer( int[]* list) { *list ~= 2; *list ~= 4; return true; } auto future = vibe.core.concurrency.async(&ListManipulator, list); future.getResult(); writeln(list); > prints empty list future = vibe.core.concurrency.async(&ListManipulatorPointer, &list); future.getResult(); writeln(list); > prints [2,4] } Why passing the pointer works meanwhile passing as reference does nothing? I feel that is more D issue than vibe.d which I can learn something I hope. Erdem Looks like a bug in vibe: https://github.com/vibe-d/vibe-core/blob/master/source/vibe/core/concurrency.d#L1141 The function async doesn't use auto ref on ARGS. So the arguments are value copies through. If it used auto ref all the way through then it'd probably work: --- import std; void async(CALLABLE, ARGS...)(CALLABLE callable, auto ref ARGS args) { callable(args); } void main() { int[] list; bool ListManipulator(ref int[] list) { list ~= 2; list ~= 4; return true; } async(&ListManipulator, list); writeln(list); }
Re: Hum Humm, Typedef
On Saturday, 30 November 2019 at 18:15:47 UTC, Treebeard wrote: Hoom, hum, I met a dark forest of complains from the compilers here. [...] /me thinks it's a bug Pushed a pr. Let's see. https://github.com/dlang/phobos/pull/7298
How do you find the struct types in a module? - getting Error: unknown
Hi, I'm trying to get a typed list of structs in my current module that matches certain criteria. Something like: module mod; struct X {} struct Y {} alias allTypes = ListOfTypes!mod; But I'm having a bit of trouble. I have this so far: template ListOfTypes(alias T) { import std.meta; enum isStruct(string m) = is(mixin(m) == struct); enum types = Filter!(isStruct, __traits(allMembers, T)); alias toType(string m) = mixin(m); alias all = staticMap!(toType, types); alias CommandGroupsOf = all; } pragma(msg, ListOfTypes!mod); But that causes an error I've never seen before: Error: unknown, please file report on issues.dlang.org onlineapp.d(30,1):while evaluating `pragma(msg, CommandGroupsOf!(mod))` Any workarounds or maybe insight in to the error?
Re: How do you find the struct types in a module? - getting Error: unknown
On Thursday, 13 February 2020 at 15:38:37 UTC, Steven Schveighoffer wrote: On 2/13/20 9:47 AM, aliak wrote: [...] Not sure about your error, but here is a working version (don't use mixins, use __traits(getMember)): import std.meta; template ListOfStructs(alias mod) { enum isStruct(string m) = is(__traits(getMember, mod, m) == struct); alias getMember(string m) = __traits(getMember, mod, m); alias ListOfStructs = staticMap!(getMember, Filter!(isStruct, __traits(allMembers, mod))); } -Steve It works without the mixin indeed! Thank you!
Is deprecating a template supposed to work?
Is this suppose to give a deprecation error message? deprecated("a") alias A(T) = B!T; template B(T) { alias B = T; } void main() { A!int a; // should this cause a message "a" ? } ?? Or am I using it wrong maybe?
Re: Is deprecating a template supposed to work?
On Thursday, 20 February 2020 at 23:21:23 UTC, MoonlightSentinel wrote: On Thursday, 20 February 2020 at 22:31:16 UTC, aliak wrote: Is this suppose to give a deprecation error message? deprecated("a") alias A(T) = B!T; template B(T) { alias B = T; } void main() { A!int a; // should this cause a message "a" ? } ?? Or am I using it wrong maybe? It's a bug, see https://issues.dlang.org/show_bug.cgi?id=20190 Ah, I see. Thanks!
Re: in not working for arrays is silly, change my view
On Monday, 2 March 2020 at 15:50:08 UTC, Steven Schveighoffer wrote: On 3/2/20 6:39 AM, JN wrote: On Saturday, 29 February 2020 at 21:56:51 UTC, Ali Çehreli wrote: Because you mentioned canFind, I think you want the semantics to be "is there an element with this value." If so, it would be confusing to use the same operator for two different things: For associative arrays, it means "is there an element accessible with this key." Does it? I always viewed it as "is this value in list of keys" Array keys are the element index.. So essentially: int[int] c1; int[] c2 = new int[4]; c1[3] = 10; c2[3] = 10; assert(3 in c1); // true assert(3 in c2); // what should this do? -Steve If in were to mean "is this value in list of keys" then to be consistent: 3 in c2 == 3 < c2.length
Re: in not working for arrays is silly, change my view
On Monday, 2 March 2020 at 15:47:26 UTC, Steven Schveighoffer wrote: On 3/2/20 6:52 AM, Andrea Fontana wrote: On Saturday, 29 February 2020 at 20:11:24 UTC, Steven Schveighoffer wrote: 1. in is supposed to be O(lg(n)) or better. Generic code may depend on this property. Searching an array is O(n). Probably it should work if we're using a "SortedRange". int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto p = assumeSorted(a); assert(3 in p); That could work. Currently, you need to use p.contains(3). opIn could be added as a shortcut. It only makes sense if you have it as a literal though, as p.contains(3) isn't that bad to use: assert(3 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].assumeSorted); -Steve There's no guarantee that checking if a value is in a sorted list is any faster than checking if it's in a non sorted list. It's why sort usually switches from a binary-esque algorithm to a linear one at a certain size. The list could potentially need to be _very_ large for p.contains to make a significant impact over canFind(p) AFAIK. Here's a small test program, try playing with the numbers and see what happens: import std.random; import std.range; import std.algorithm; import std.datetime.stopwatch; import std.stdio; void main() { auto count = 1_000; auto max = int.max; alias randoms = generate!(() => uniform(0, max)); auto r1 = randoms.take(count).array; auto r2 = r1.dup.sort; auto elem = r1[uniform(0, count)]; benchmark!( () => r1.canFind(elem), () => r2.contains(elem), )(1_000).writeln; } Use LDC and -O3 of course. I was hard pressed to get the sorted contains to be any faster than canFind. This begs the question then: do these requirements on in make any sense? An algorithm can be log n (ala the sorted search) but still be a magnitude slower than a linear search... what has the world come to 🤦♂️ PS: Why is it named contains if it's on a SortedRange and canFind otherwise?
Re: in not working for arrays is silly, change my view
On Monday, 2 March 2020 at 21:33:37 UTC, Steven Schveighoffer wrote: On 3/2/20 3:52 PM, aliak wrote: On Monday, 2 March 2020 at 15:47:26 UTC, Steven Schveighoffer wrote: On 3/2/20 6:52 AM, Andrea Fontana wrote: On Saturday, 29 February 2020 at 20:11:24 UTC, Steven Schveighoffer wrote: 1. in is supposed to be O(lg(n)) or better. Generic code may depend on this property. Searching an array is O(n). Probably it should work if we're using a "SortedRange". int[] a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; auto p = assumeSorted(a); assert(3 in p); That could work. Currently, you need to use p.contains(3). opIn could be added as a shortcut. It only makes sense if you have it as a literal though, as p.contains(3) isn't that bad to use: assert(3 in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].assumeSorted); There's no guarantee that checking if a value is in a sorted list is any faster than checking if it's in a non sorted list. It's why sort usually switches from a binary-esque algorithm to a linear one at a certain size. Well of course! A binary search needs Lg(n) comparisons for pretty much any value, whereas a linear search is going to end early when it finds it. So there's no guarantee that searching for an element in the list is going to be faster one way or the other. But Binary search is going to be faster overall because the complexity is favorable. Overall tending towards infinity maybe, but not overall on the average case it would seem. Branch prediction in CPUs changes that in that with a binary search it is always a miss. Whereas with linear it's always a hit. The list could potentially need to be _very_ large for p.contains to make a significant impact over canFind(p) AFAIK. Here's a small test program, try playing with the numbers and see what happens: import std.random; import std.range; import std.algorithm; import std.datetime.stopwatch; import std.stdio; void main() { auto count = 1_000; auto max = int.max; alias randoms = generate!(() => uniform(0, max)); auto r1 = randoms.take(count).array; auto r2 = r1.dup.sort; auto elem = r1[uniform(0, count)]; auto elem = r1[$-1]; // try this instead benchmark!( () => r1.canFind(elem), () => r2.contains(elem), )(1_000).writeln; } Use LDC and -O3 of course. I was hard pressed to get the sorted contains to be any faster than canFind. This begs the question then: do these requirements on in make any sense? An algorithm can be log n (ala the sorted search) but still be a magnitude slower than a linear search... what has the world come to 🤦♂️ PS: Why is it named contains if it's on a SortedRange and canFind otherwise? A SortedRange uses O(lgn) steps vs. canFind which uses O(n) steps. canFind is supposed to tell the reader that it's O(n) and contains O(lgn)? If you change your code to testing 1000 random numbers, instead of a random number guaranteed to be included, then you will see a significant improvement with the sorted version. I found it to be about 10x faster. (most of the time, none of the other random numbers are included). Even if you randomly select 1000 numbers from the elements, the binary search will be faster. In my tests, it was about 5x faster. Hmm... What am I doing wrong with this code? And also how are you compiling?: void main() { auto count = 1_000_000; auto max = int.max; alias randoms = generate!(() => uniform(0, max - 1)); auto r1 = randoms.take(count).array; auto r2 = r1.dup.sort; auto r3 = r1.dup.randomShuffle; auto results = benchmark!( () => r1.canFind(max), () => r2.contains(max), () => r3.canFind(max), )(5_000); results.writeln; } $ ldc2 -O3 test.d && ./test [1 hnsec, 84 μs and 7 hnsecs, 0 hnsecs] Note that the compiler can do a lot more tricks for linear searches, and CPUs are REALLY good at searching sequential data. But complexity is still going to win out eventually over heuristics. Phobos needs to be a general library, not one that only caters to certain situations. General would be the most common case. I don't think extremely large (for some definition of large) lists are the more common ones. Or maybe they are. But I'd be surprised. I also don't think phobos is a very data-driven library. But, that's a whole other conversation :) -Steve
Re: in not working for arrays is silly, change my view
On Monday, 2 March 2020 at 23:27:22 UTC, Steven Schveighoffer wrote: What I think is happening is that it determines nobody is using the result, and the function is pure, so it doesn't bother calling that function (probably not even the lambda, and then probably removes the loop completely). I'm assuming for some reason, the binary search is not flagged pure, so it's not being skipped. Apparently you're right: https://github.com/dlang/phobos/blob/5e13653a6eb55c1188396ae064717a1a03fd7483/std/range/package.d#L11107 If I change to this to ensure side effects: bool makeImpure; // TLS variable outside of main ... auto results = benchmark!( () => makeImpure = r1.canFind(max), () => makeImpure = r2.contains(max), () => makeImpure = r3.canFind(max), )(5_000); writefln("%(%s\n%)", results); // modified to help with the comma confusion I now get: 4 secs, 428 ms, and 3 hnsecs 221 μs and 9 hnsecs 4 secs, 49 ms, 982 μs, and 5 hnsecs More like what I expected! A damn! And here I was thinking that branch prediction made a HUGE difference! Ok, I'm taking my tail and slowly moving away now :) Let us never speak of this again. -Steve
Re: Safely wrapping an uncopyable struct to implement an interface
On Wednesday, 4 March 2020 at 12:03:48 UTC, Gregor Mückl wrote: Hi! I've just created a situation in my code that is summarized by the following example. I don't know how to solve it with @safe code. A third party library provides a struct that is not copyable: // provided by third party struct Foo { @disable this() @safe; @disable this(ref return scope Foo other) @safe; void magic() @safe; } What I want to do is to provide a safe wrapper around it that adapts to another interface: // intended common interface interface IWrapper { void bar() @safe; } Now, the obvious way to wrap this fails: class FooWrapper : IWrapper { Foo f; this(Foo f) @safe { this.f = f; // this fails because it would be a copy } override void bar() @safe { f.magic(); } } If Foo were a class, f would be a reference and everything would be fine. But f is a struct that can't be copied and taking a pointer to f makes FooWrapper obviously unsafe. How could I solve this? I've come up with a workaround for my actual use case that doesn't need to use the uncopyable struct this way. But I'm curious if I'm missing something regarding references to structs. You can use move maybe? : https://dlang.org/library/std/algorithm/mutation/move.html So this.f = f.move; But you should be aware that it could cause problems when f has pointers to its internals. I.e. if Foo had a pointer to it's own member then the value of of that pointer to me "copied" over to this.f, but the address of the member in this.f is different that the original f's member address.
Re: Pattern matching via switch?
On Saturday, 14 March 2020 at 19:04:28 UTC, 12345swordy wrote: I.E. switch (object) case Type1 t1: case Type2 t2: case Type3 t3: You can use the sumtype package (https://code.dlang.org/packages/sumtype): alias T = SumType!(Type1, Type2, Type3); T(object).match!( (Type1 t1) => "t1", (Type2 t2) => "t2", (Type3 t3) => "t3", ); Or you can make a quick template like: template switch_(funs...) { auto switch_(T)(auto ref T t) { static foreach (fun; funs) { static if (is(typeof(fun(T.init { return fun(t); } } } } struct A {} struct B {} struct C {} void main() { auto a = C(); a.switch_!( (A _) => "a", (B _) => "b", (C _) => "c", ).writeln; } The template above is a quick fix and will have some holes though. Off the top of my head if more than one lambda "fits" there'll be problems.
Re: dub sourceFiles
On Tuesday, 31 March 2020 at 15:23:48 UTC, Anonymouse wrote: I have a library package that I split up into subpackages, but I'm having to do mental gymnastics to make it only compile the files I want. The problem is that even if you specify some `sourceFiles`, it will build everything under the sun inside `sourcePaths`, which defaults to "source" or "src" depending on availability. There's no way to set it to an empty string, or something that doesn't exist. ```sdl name "stuff" targetType "library" subPackage { name "foo" sourceFiles \ "source/foo.d" } subPackage { name "bar" sourceFiles \ "source/bar.d" \ "source/common.d" } ``` $ dub build -v :foo [...] /usr/bin/dmd -Isource source/foo.d source/bar.d source/common.d Since I didn't specify any `sourcePaths`, it here defaults to "source" and my subpackage only asking for "foo.d" was handed all of the files anyway. What is the preferred solution here? 1. Use `excludedSourceFiles` and exclude files not to be compiled. Mental gymnastics needed when you have 12 files (the actual case). 2a. Keep source tree in something that isn't named "source" or "src", but keep an empty one around for dub to auto-include nothing from. I kind of want to avoid this. 2b. Keep real source files in "source", but declare `sourcePaths` to point to a dummy empty "ignoreme" directory. Crude but technically works. 3. Something else? Surely I'm not the first to run into this. I could set up the subpackages to each have its own directory (2a), but I'd end up with twelve, not including the empty "source" acting as bait for dub. Maybe this will help you: https://github.com/aliak00/dub-subpackages I think it falls under the something else category. The "lib" folder does have a source directory but I'm pretty sure you can remove that and it will still work and compile only the sub projects you want it to. But, dub is sometimes a mystery in how it works so shout if the above doesn't work!
Re: Integration tests
On Friday, 17 April 2020 at 16:56:57 UTC, Russel Winder wrote: Hi, Thinking of trying to do the next project in D rather than Rust, but… Rust has built in unit testing on a module basis. D has this so no problem. Rust allows for integration tests in the tests directory of a project. These are automatically build and run along with all unit tests as part of "cargo test". Does D have any integrated support for integration tests in the way Rust does? D does not recognise any special testing directories afaik. But you'll get the same affect as in rust if you have your integration tests in a file that is not the modules you are testing and run it after building the main library - or during even. With Dub it's quite easy to set up, you can see the optional package as an example [0]. There's a tests directory that does not have access to the optional package's internals. There's also a unittest-compat configuration in dub.json that tests the package alongside vibed (another d package) For auto mocking, the only thing I've see that provides some functionality is the unit-threaded package. But I've never tried it. [0]: https://github.com/aliak00/optional
Re: Option and Result [was Integration tests]
On Tuesday, 21 April 2020 at 16:30:15 UTC, Russel Winder wrote: On Mon, 2020-04-20 at 20:19 +, aliak via Digitalmars-d-learn wrote: […] [0]: https://github.com/aliak00/optional Rust has Option and Result, and most languages are rapidly introducing at least Option if not Result – and yes it is almost certain all this comes from Haskell. Yeah it's a great abstraction that's part of modern languages now. Some static languages are even building syntax for it right in (e.g. swift, kotlin, v, zig - to name a few). There've been a few attempts at building a Result type: https://code.dlang.org/search?q=expect And here: https://github.com/aliak00/ddash/blob/master/utils/source/ddash/utils/expect.d Is Option intended for adding to Phobos? Not that I am aware of. There was an attempt to PR an Option type way back when which never made it: https://github.com/dlang/phobos/pull/3915 There was a post here: https://forum.dlang.org/thread/hqtdekjtdgbhhbjgy...@forum.dlang.org
Re: Integration tests
On Wednesday, 22 April 2020 at 10:32:48 UTC, Russel Winder wrote: Now I discover Python, Rust, and Go have far nicer abstractions for writing Internet code than D does. Does D really not have a TcpListener abstraction? It really doesn't :( And D has so much potential as server tech with the potential combination of fibers + TLS + shared + static introspection. The package Vibe-d is quite nice though. I don't know if you've tried it but it's very simple to get a listener up with it. To date all I can get is: std.socket.SocketOSException@std/socket.d(2792): Unable to bind socket: Bad file descriptor when trying to open a TCP server on 127.0.0.1:5, with Python, Rust, or Go it all worked first time. This is really sad given D has so many advantages over Rust. :-(
Can't get dub dustmite to work
Trying to get dub dustmite to work, but I keep getting "initial test fails" This is the error from a vanilla dub test: ``` result ~wip: building configuration "result-test-unittest"... inout(SumType!(int, FailureContainer)) ../../.dub/packages/sumtype-0.9.4/sumtype/src/sumtype.d(1322,4): Error: static assert: "handler #1 of type Optional!(Exception) function(FailureContainer container) pure nothrow @nogc @safe never matches" ../../.dub/packages/sumtype-0.9.4/sumtype/src/sumtype.d(1165,14): instantiated from here: matchImpl!(inout(SumType!(int, FailureContainer))) source/result/result.d(136,20):instantiated from here: match!(inout(SumType!(int, FailureContainer))) tests/result.d(20,20):instantiated from here: Result!(int, Exception) dmd failed with exit code 1. ``` Then I run this dub dustmite command: dub dustmite -b unittest ../dubdust --compiler-regex="never matches" And I get: ``` ... Loading /Users/aliak/dev/dubdust/vibe-d/web/vibe/web/web.d None => No Hint: use --no-redirect to see test script output Hint: read https://github.com/CyberShadow/DustMite/wiki#initial-test-fails object.Exception@DustMite/dustmite.d(295): Initial test fails: Test script "/usr/local/Cellar/dub/1.20.0/bin/dub dustmite --vquiet --test-package=result --build=unittest --config=library \"--compiler=dmd\" \"--compiler-regex=never matches\"" exited with exit code 3 (failure) ``` * --no-redirect doesn't work in dub dustmite. * I tried adding --compiler-status=1 with the same result * I tired --combined with the same result My dub.json for the unittest configuration is (incase that matters): { "name": "unittest", "importPaths": [ "./tests" ], "sourcePaths": [ "./tests" ] }, Thanks for any help!
Re: Can't get dub dustmite to work
On Saturday, 25 April 2020 at 19:00:55 UTC, Anonymouse wrote: On Saturday, 25 April 2020 at 09:38:59 UTC, aliak wrote: Then I run this dub dustmite command: dub dustmite -b unittest ../dubdust --compiler-regex="never matches" I have had zero luck with dustmite via dub. I would honestly recommend that you create a shell script that does `dub test 2>&1 | grep "never matches"`, and just use that as a tester with dustmite directly. Ok I got it working with that but it resulted in the wrong output (it was a bad test case basically" But expanding the shell script to dub test 2>&1 | grep 'Error: static assert: \"handler #0 of type `Optional!(Exception) function(FailureContainer container) pure nothrow @nogc @safe` never matches\"' now results in ... Loading ./source/result/failure.d Loading ./source/result/package.d Loading ./source/result/result.d Loading ./tests/result.d None => No Hint: use --no-redirect to see test script output Hint: read https://github.com/CyberShadow/DustMite/wiki#initial-test-fails object.Exception@DustMite/dustmite.d(295): Initial test fails: Test script "dub test 2>&1 | grep 'Error: static assert: \"handler #0 of type never matches\"'" exited with exit code 1 (failure) ??:? _Dmain [0x10c56cf5e] This is the full dustmite command: dustmite --force . "dub test 2>&1 | grep 'Error: static assert: \"handler #0 of type `Optional!(Exception) function(FailureContainer container) pure nothrow @nogc @safe` never matches\"'"
Re: Can't get dub dustmite to work
On Saturday, 25 April 2020 at 18:52:45 UTC, Andre Pany wrote: How do you call dub test causing the issue? Maybe there is a difference in the configuration/build type. I'm sorry I didn't follow. You mean like: "dub test" ?? I dont pass anything to the -b or -c flag if that's what you mean? Also a side remark. You cannot use the output of dmd when colouring is on. Dmd lies because the backticks used for colouring are not shown. But without them, regex search is failing. Yeah, that's a good tip. This output is because of a static assert in the sumtype library. I also wonder whether dub Dustmite should be enhanced to search for a plain text too. Because while using regex search there might be characters which have a regex meaning while user just want a simple text search. This could also cause issues. Kind regards Andre
Re: Can't get dub dustmite to work
On Monday, 27 April 2020 at 06:23:08 UTC, Andre Pany wrote: On Sunday, 26 April 2020 at 22:07:56 UTC, aliak wrote: On Saturday, 25 April 2020 at 18:52:45 UTC, Andre Pany wrote: [...] I'm sorry I didn't follow. You mean like: "dub test" ?? I dont pass anything to the -b or -c flag if that's what you mean? [...] Yeah, that's a good tip. This output is because of a static assert in the sumtype library. Yes, that was my question. `dub test` will use configuration `unittest`, therefore you have to pass the configuration `unittest` to `dub dustmite` too. Kind regards André Ah ok. Yes I was passing the unittest confit to dub dustmite.
Re: vibe.d and my first web service
On Saturday, 18 July 2020 at 09:10:04 UTC, Mr. Backup wrote: Hello, I wanted to create simple web service to start learning more about D lang and compare with another languages. I have used "dub init -t vibe.d" to create basic example: [...] Think it's just Vibe.d: I had a similar issue: https://github.com/vibe-d/vibe.d/issues/2436 And this is still open (default server doesn't clean itself up): https://github.com/vibe-d/vibe.d/issues/2245
Re: Is it possible to "overload" based on visibility?
On Wednesday, 23 September 2020 at 18:38:53 UTC, 60rntogo wrote: There are really two questions here, one that I intended to ask and one that came out while I was trying to figure out the answer. Consider this simple code: [...] Yeah, you can make a property setter: private void x(int newValue) { _x = newValue } 2. Is the behavior that allows me to call the private method intended? This is such a blatant violation of encapsulation that it feels like a bug either in the language or the implementation. Definitely sounds like a bug! Feels like this has got to be a regression because I just tried this: struct Foo { private void f() {} void f(int i) {} } And Foo.f() is callable from outside the module: https://run.dlang.io/is/FVyw7u
Re: Is it possible to "overload" based on visibility?
On Wednesday, 23 September 2020 at 19:27:13 UTC, Steven Schveighoffer wrote: This is a bug in the language. 🤯😆
Re: Renaming Flag!"" in API
On Monday, 12 October 2020 at 10:24:44 UTC, FreeSlave wrote: Let's say I use Flag type named 'myflagname' in API like this: import std.typecons; void func(Flag!"myflagname" flag) { //... } void main() { func(Yes.myflagname); } Later I realize that 'myflagname' is a bad name and I want to change it to something else. But if I do so, I break the existing code using this API as Flag with different name will be a different type and Yes.myflagname and No.myflagname won't fit in. I can't use alias as Yes and No relies on string literal. Can this issue overcome somehow? Looks like a fundamental flaw with std.typecons.Flag. One of the reason's Flag is there is because of what's known as the boolean trap [0]. If someone changes the name of a parameter, that can potentially mean the semantics have changed. Should Flag work then? And if it should, why not straight up bool? https://wiki.qt.io/API_Design_Principles#The_Boolean_Parameter_Trap
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 14:19:35 UTC, Steven Schveighoffer wrote: On 5/21/18 8:15 AM, SrMordred wrote: Right, so this should´n be working I think. struct SomeStruct { void foo(int); } SomeStruct s; s.foo = 10; I thought that only with @property this will work. That was the plan, but it got derailed. Whoever wrote that original line of code, they need a stern talking-to. -Steve While wearing the naughty pointy hat and sitting in a corner :p
Re: UFCS syntax I never saw before.
On Monday, 21 May 2018 at 18:53:19 UTC, Jonathan M Davis wrote: writeln = "foo"; is legal, and it's dumb, but it hasn't mattered much in practice. So, causing a bunch of code breakage in order to disallow it is unlikely to go over well. It would also then make getters and setters inconsistent in that setters would require @property and getters wouldn't. How much that matters is debatable, but it does make such a change less palatable. [...] Can't assignment to a function be fixed though? Are there any cases where fixing that will cause problems for @property free functions because they all must take more that one parameter i assume. It's quite a big wart so we don't have to fix all of @property at least, but that should be fixed if fixing it does not crap on UFCS and @property free functions.
Re: UFCS syntax I never saw before.
On Tuesday, 22 May 2018 at 13:59:16 UTC, Steven Schveighoffer wrote: The derailed plan was to leave alone the ability to call no-arg functions without parentheses, but to REQUIRE @property to call an argument-taking function with the assignment style. See the DIP here: https://wiki.dlang.org/DIP23 Written by Walter and Andrei. I can't remember why it didn't happen. -Steve Aha. Thanks for the link! It feels like the only difference between a no-arg function that is @property and one that is not is that the former could be invoked with optional parentheses and the latter should be illegal with parentheses. Whereas an argument taking function marked as @property should probably allow read or write operations depending on whether or not it's invoked with an implicit first argument or not: @property int f(int) { ... } 1.f; // read op f = 1; // write op And to make parentheses illegal as well of course.
Re: UFCS syntax I never saw before.
On Tuesday, 22 May 2018 at 14:33:20 UTC, Jonathan M Davis wrote: A free function with a single argument works just fine as a setter property. e.g. you could do something like void env(Tuple!(string, string)[] str) { // set environment variables } env = [tuple("foo", "bar")]; is perfectly legal. I question that there are many cases where such a function would be considered good design, but basically any case where it would make sense to have a function act like a global variable is currently allowed but would be disallowed if you couldn't have a setter property with only one argument. - Jonathan M Davis That can be attributed with @property if the developer intends for it to be used in that way, else should be illegal.
Re: UFCS syntax I never saw before.
On Thursday, 24 May 2018 at 22:03:38 UTC, aliak wrote: It feels like the only difference between a no-arg function that is @property and one that is not is that the former could be invoked with optional parentheses and the latter should be illegal with parentheses. Edit: err... other way around!
Assigning a method name to a variable and then calling it with an object
Hi, I was essentially trying to do this: struct S { void f() {} } auto f = S.f; // f becomes void function(S) ?? S s; f(s); Is something like that possible? Cheers, - Ali
Re: Assigning a method name to a variable and then calling it with an object
On Thursday, 24 May 2018 at 23:08:29 UTC, Basile B. wrote: On Thursday, 24 May 2018 at 23:03:21 UTC, aliak wrote: Hi, I was essentially trying to do this: struct S { void f() {} } auto f = S.f; // f becomes void function(S) ?? S s; f(s); Is something like that possible? Cheers, - Ali Sure: ``` import std.stdio; void main(string[] args) { struct S { void f() {"yeah possible".writeln;} } void delegate() f; f.funcptr = &S.f; S s; f.ptr = &s; s.f(); } ``` It's just that you have to learn the ABI of D delegates. There are two members: .funcptr (function) and .ptr (context, i.e the "this"). ahh, gracias!
Re: WTF! new in class is static?!?!
On Thursday, 7 June 2018 at 21:32:54 UTC, Jonathan M Davis wrote: struct S { int* ptr = new int(42); } Is that supposed to compile? -> https://run.dlang.io/is/SjUEOu Error: cannot use non-constant CTFE pointer in an initializer &[42][0]
Re: How to list all the manifest constants in a class or struct
On Sunday, 17 June 2018 at 02:44:38 UTC, Heromyth wrote: Here is a struct named S: struct S { enum X = 10; enum Y { i = 10 } enum Z = "str"; struct S {} class C {} static int sx = 0; __gshared int gx = 0; shared void g(); } I want list all then the manifest constants in it. I searched the std.traits and this forums, but get nothing. Maybe, my real question is how to get the storage class for a member in a class or struct. Thanks. I think this bolts.isManifestAssignable [1] will get you partially there. The place where it'll fail though is a static immutable (since they are assignable to manifest constants) but you can filter those by seeing if you can take the address, something like: foreach (m; __traits(allMembers, T)) { if (isManifestAssignable!(T, m) && !is(typeof(mixin("&T."~m))) { // it's a manifest constant ... (?) } } There of course might be edge cases I can't think of/don't know about though. Cheers, - Ali http://bolts.dpldocs.info/bolts.traits.isManifestAssignable.html
Re: UCFS does not work for nested functions?
On Monday, 18 June 2018 at 14:19:30 UTC, Steven Schveighoffer wrote: On 6/18/18 7:16 AM, Bastiaan Veelo wrote: On Sunday, 18 May 2014 at 08:15:08 UTC, Steffen Wenz wrote: Hi, Just noticed that using UFCS does not work for nested functions, and was wondering whether that's intended, and what the rationale behind it is: I just had the same question. I can imagine that the context pointer of nested functions complicates things, but making `bar` `static` does not help. Has anything changed in recent years regarding the difficulty of implementing UFCS for nested functions? Would it be easier to only support static nested functions? ``` void main() { static void bar(int x) {} int x; x.bar(); // Error: no property 'bar' for type 'int' } ``` It's never been supported, and likely will not be. I think the idea is that you can override expected behavior inside by accidentally defining some function locally with the same name. -Steve Wondering how this is different than with non-nested functions? If a global function has the same name as a member function then the member function takes precedence. So wouldn't the same thing just apply here if it were supported? Cheers, - Ali
Re: scope(success) lowered to try-catch ?
On Monday, 18 June 2018 at 12:48:46 UTC, Steven Schveighoffer wrote: On 6/17/18 11:58 PM, Neia Neutuladh wrote: [...] Yep, it's a good point. But also not the only way to do this. If you are returning void, just a goto would work: [...] I'm quite a noob when it comes to compiler stuff, and I see how this can be optimized when there're no exceptions, but I wonder what scope(success) actually means though without exceptions in play. It's just scope(exit) then right or? Cheers, - Ali
Re: UCFS does not work for nested functions?
On Monday, 18 June 2018 at 17:58:11 UTC, Steven Schveighoffer wrote: What then can happen is that your local calls can get hijacked from outside the module, if someone happens to define something later that you happened to import. D tries to avoid such possibilities. There's not much precedent for local symbols being overridden by module-level symbols. -Steve I thought that happens already with non-nested functions: module a; struct A { void f(); // assume it's added later } module b; import a; void f(A) { } void g() { auto x = A(); a.f(); // this would be calling local f until someone added A.f } Or I misunderstood what you said? Cheers, - Ali PS: This is something I've worried about before actually [1] when I was more of a noob than now, but I've come to accept I guess :) ... though I could still be misunderstanding things of course :/ https://forum.dlang.org/post/crcbaautgmrglhzvx...@forum.dlang.org
Re: UCFS does not work for nested functions?
On Monday, 18 June 2018 at 19:26:47 UTC, Steven Schveighoffer wrote: On 6/18/18 2:58 PM, aliak wrote: [...] It's the same in the fact that your call is silently switched to a different call. However, in the current syntax, an external entity CANNOT override a local function. When you call the nested function, it's the nested function, no matter what else occurs outside (even in the local module). There is no precedent for local functions to be overridden by module-level functions. [...] Ah I see. So it's basically that locals take priority, but if you allow them to UFCS then that's not true anymore because members need to take priority. Ok yep, that makes sense. Thanks !
template sequence parameters treats member functions differently?
Hi, I'm having some issues with template sequence parameters, it seems they are not typed as delegates inside a template, but are outside. I.e. template T(V...) { alias T = typeof(&V[0]); } struct S { void f() {} } S s; pragma(msg, T!(s.f)); // void function() pragma(msg, typeof(&s.f)); // void delegate() How come the output is different? Is it supposed to be the same? What I'm trying to do is write a template that can give me a tuple of types for all values of the sequence passed in, so that I can index in to the type tuple. Seems to work well except for this member function part, working source here: https://run.dlang.io/is/TBXHlY Specifically the commented out line is what I would like to be able to get working if possible. Thanks for any help, - Ali
Re: Wrapping a forward range in another forward range
On Sunday, 24 June 2018 at 20:33:32 UTC, Rudy Raab wrote: So I have an XLSX (MS Excel 2007+ file format) library that I wrote (https://github.com/TransientResponse/dlang-xlsx) that I recently converted from std.xml to dxml. That went well and it still works (much faster too). [...] I think it's the isSomeChar!(ElementType!R), not the isRandomAccessRange (because string isSomeString and !isSomeChar)? Cheers, - Ali
Re: overload .
On Monday, 25 June 2018 at 13:37:01 UTC, Mr.Bingo wrote: One can overload assignment and dispatch so that something like A.x = ... is valid when x is not a typical member but gets resolved by the above functions. Therefore, I can create a member for assignment. How can I create a member for getting the value? A.x = 3; // Seems to get translated in to A.opDispatch!("x")(3) works but foo(A.x); // fails and the compiler says x does not exist I need something consistent with opDot. I am trying to create "virtual"(not as in function) fields and I can only get assignment but not accessor. A.x is translated in to A.opDispatch!"x" with no args. So I guess you can overload or you can static if on a template parameter sequence: import std.stdio; struct S { auto opDispatch(string name, Args...)(Args args) { static if (!Args.length) { return 3; } else { // set something } } } void main() { S s; s.x = 3; writeln(s.x); } Cheers, - Ali
Re: overload .
On Monday, 25 June 2018 at 15:39:09 UTC, Mr.Bingo wrote: On Monday, 25 June 2018 at 13:58:54 UTC, aliak wrote: A.x is translated in to A.opDispatch!"x" with no args. So I guess you can overload or you can static if on a template parameter sequence: import std.stdio; struct S { auto opDispatch(string name, Args...)(Args args) { static if (!Args.length) { return 3; } else { // set something } } } void main() { S s; s.x = 3; writeln(s.x); } Cheers, - Ali Ok, for some reason using two different templated failed but combining them in to one passes: auto opDispatch(string name, T)(T a) auto opDispatch(string name)() Maybe it is a bug in the compiler that it only checks one opDispatch? Two opDispatchs as in: import std.stdio: writeln; struct S { void opDispatch(string name, T)(T t) { writeln(t); } auto opDispatch(string name)() { writeln("ret"); return 4; } } void main() { S s; s.x; s.x = 4; } ?? The above seems to work fine. Or maybe you meant something else?
Re: template sequence parameters treats member functions differently?
On Monday, 25 June 2018 at 15:06:42 UTC, Steven Schveighoffer wrote: On 6/24/18 5:19 PM, aliak wrote: [...] No, because the alias is an alias to the function, not the delegate. The act of taking the address creates the delegate, where the delegate's ptr is the context pointer (i.e. s), and the funcptr is the function that accepts the pointer (i.e. S.f). When you pass in s.f to an alias, you are actually passing in S.f. It's the fact that you are looking in the *namespace* of s when you do the alias. The &s.f is special for the compiler, and can't be deferred to later. Ahh, I see. Ah well. So not really much i can do here with this then I guess. Thanks for explaining though! BUT, I'm thinking this may be fixable, as it's inconsistent with inner functions: auto foo(alias x)() { return x(); } struct S { int bar() { return 42; } // int baz() { return foo!bar; } // nope } void main() { S s; int bar() { return 42; } assert(foo!bar() == 42); // ok // assert(foo!(s.bar) == 42); // nope int baz() { return s.bar; } assert(foo!baz() == 42); // ok! } I don't see any reason why the alias is to the function and not the contexted function. I don't see how it's any different from the ones which use inner functions. -Steve I can only agree - me no see either. And having no clue as to how the compiler is implemented, I cannot even conjecture :)
Re: template sequence parameters treats member functions differently?
On Monday, 25 June 2018 at 18:59:37 UTC, Steven Schveighoffer wrote: On 6/25/18 2:51 PM, aliak wrote: On Monday, 25 June 2018 at 15:06:42 UTC, Steven Schveighoffer wrote: I don't see any reason why the alias is to the function and not the contexted function. I don't see how it's any different from the ones which use inner functions. I can only agree - me no see either. And having no clue as to how the compiler is implemented, I cannot even conjecture :) Well, it's worth an enhancement request in any case. -Steve doneo: https://issues.dlang.org/show_bug.cgi?id=19026
anyway to pass the context of an inner type to a template so it can be constructed?
This currently fails unless you mark the class as static: auto construct(T)() { return new T; } void main() { class C {} auto s = construct!C; } So wondering if there's anything that can be done to get the above working? Or if there isn't then how could the compiler be enhanced to allow for something like this if possible? === The use case is for a non-nullable type, where I want to guarantee that the value inside will never be null. I can't do it for inner classes though. And I can't allow the user to do something like: void main() { class C {} auto s = construct(new C); } Because I can't guarantee that's not null. Cheers, - Ali
Re: anyway to pass the context of an inner type to a template so it can be constructed?
On Wednesday, 27 June 2018 at 14:01:03 UTC, Alex wrote: On Wednesday, 27 June 2018 at 12:02:10 UTC, aliak wrote: === The use case is for a non-nullable type, where I want to guarantee that the value inside will never be null. I can't do it for inner classes though. And I can't allow the user to do something like: void main() { class C {} auto s = construct(new C); } Because I can't guarantee that's not null. Cheers, - Ali Is there any reason, why you don't want to use a struct? An instance of such is never null, still having access to its context, if it is a function. Sorry, by non-nullable I meant not null. It's that construct produces a wrapper type that has an internal value that I want to guarantee is not null. So whether T is a struct or class is dependent on the user of construct. - Ali
Re: anyway to pass the context of an inner type to a template so it can be constructed?
On Wednesday, 27 June 2018 at 19:28:37 UTC, Timoses wrote: Can't seem to avoid using mixin in main.. hehe yeah I see, didn't think of trying mixins, worth a shot! It seems like you had fun at least ;)
Re: Nullable!T with T of class type
On Thursday, 28 June 2018 at 18:10:07 UTC, kdevel wrote: On Tuesday, 26 June 2018 at 21:54:49 UTC, Jonathan M Davis wrote: [H]onestly, I don't understand why folks keep trying to put nullable types in Nullable in non-generic code. How do you signify that a struct member of class type is optional? So there're no optional type in D (ala Swift, Kotlin, Scala, etc). There are a number of workarounds you can use to achieve the same type of behavior. You can use ranges to denote "some" value or no value (empty range). But it's a bit inconvenient and the APIs to get that running say nothing about intent. You can create a lightweight Maybe type: https://stackoverflow.com/questions/27241908/maybe-types-in-d I've implemented an optional type as well that includes safe dispatching, but it's not @nogc right now -> https://github.com/aliak00/optional I think there's another optional type on dub somewhere as well. But using Nullable!T just defers the problem that optional solves: if (nullable.isNull) { nullable.get.doSomething(); } vs: if (ptr !is null) { ptr.doSomething(); } meh... It's more of a tool to allow you to give any type nullability semantics. Cheers, - Ali
what's the correct way to handle unicode? - trying to print out graphemes here.
Hi, trying to figure out how to loop through a string of characters and then spit them back out. Eg: foreach (c; "👩👩👦👦🏳️🌈") { writeln(c); } So basically the above just doesn't work. Prints gibberish. So I figured, std.uni.byGrapheme would help, since that's what they are, but I can't get it to print them back out? Is there a way? foreach (c; "👩👩👦👦🏳️🌈".byGrapheme) { writeln(c.); } And then if I type the loop variable as dchar, then it seems that the family empji is printed out as 4 faces - so the code points I guess - and the rainbow flag is other stuff (also its code points I assume) Is there a type that I can use to store graphemes and then output them as a grapheme as well? Or do I have to use like lib ICU maybe or something similar? Cheers, - Ali
Re: what's the correct way to handle unicode? - trying to print out graphemes here.
On Tuesday, 3 July 2018 at 13:32:52 UTC, aliak wrote: Hi, trying to figure out how to loop through a string of characters and then spit them back out. Eg: foreach (c; "👩👩👦👦🏳️🌈") { writeln(c); } So basically the above just doesn't work. Prints gibberish. So I figured, std.uni.byGrapheme would help, since that's what they are, but I can't get it to print them back out? Is there a way? foreach (c; "👩👩👦👦🏳️🌈".byGrapheme) { writeln(c.); } And then if I type the loop variable as dchar, then it seems that the family empji is printed out as 4 faces - so the code points I guess - and the rainbow flag is other stuff (also its code points I assume) Is there a type that I can use to store graphemes and then output them as a grapheme as well? Or do I have to use like lib ICU maybe or something similar? Cheers, - Ali Hehe I guess the forum really is using D :p The two graphemes I'm talking about (which seem to not be rendered correctly above) are: family emoji: https://emojipedia.org/family-woman-woman-boy-boy/ rainbow flag: https://emojipedia.org/rainbow-flag/
Re: what's the correct way to handle unicode? - trying to print out graphemes here.
On Tuesday, 3 July 2018 at 14:43:37 UTC, Steven Schveighoffer wrote: On 7/3/18 10:37 AM, ag0aep6g wrote: On Tuesday, 3 July 2018 at 13:32:52 UTC, aliak wrote: foreach (c; "👩👩👦👦🏳️🌈") { writeln(c); } So basically the above just doesn't work. Prints gibberish. Because you're printing one UTF-8 code unit (`char`) per line. So I figured, std.uni.byGrapheme would help, since that's what they are, but I can't get it to print them back out? Is there a way? foreach (c; "👩👩👦👦🏳️🌈".byGrapheme) { writeln(c.); } You're looking for `c[]`. But that won't work, because std.uni apparently doesn't recognize those as grapheme clusters. The emojis may be too new. std.uni is based on Unicode version 6.2, which is a couple years old. Oops! I didn't realize this, ignore my message about reporting a bug. I still think it's very odd for printing a grapheme to print the data structure. -Steve Aha, ok I see. Many gracias! Though, seems by a couple years old you mean 6 years! :) Is updating unicode stuff to the latest a matter of some config file somewhere with the code point configurations that result in specific graphemes? Feels kinda ... quite bad that we're 6 years behind the current standard. Also, any reason (technical or otherwise) that we have to slice a grapheme to get it printed? Or just no one implemented something like toString or the like? It's quite non intuitive as it is right now IMO. I can't really imagine anyone figuring out that they have to slice a grapheme to get it to print 🤔 Cheers, - Ali
Re: what's the correct way to handle unicode? - trying to print out graphemes here.
On Tuesday, 3 July 2018 at 14:37:32 UTC, Adam D. Ruppe wrote: On Tuesday, 3 July 2018 at 13:32:52 UTC, aliak wrote: [...] What system are you on? Successfully printing this stuff depends on a lot of display details too, like writeln goes to a terminal/console and they are rarely configured to support such characters by default. You might actually be better off printing it to a file instead of to a display, then opening that file in your browser or something, just to confirm the code printed is correctly displayed by the other program. [...] prolly just printing `c` itself would work and if not try `c[]` but then again it might see it as multiple graphemes, idk if it is even implemented. Just 'c' didn't but 'c[]' seems like the thing to do! Thankies! Terminal on osx, and yeah you're right. Seems like just trying to paste rainbow flag right in to terminal results in the 3 separate code points
How to get an inout constructor working with a template wrapper
Hi, In the code below: struct W(T) { T val; this(T val) inout { this.val = val; } } class C {} void main() { W!C a = new C; immutable W!C b = new C; } W!C a = new C results in: "Error: cannot implicitly convert expression val of type C to inout(C)." If I remove the inout on the constructor then the error is on the other line and is: "Error: mutable method W!(C).W.this is not callable using a immutable object" If the class is changed to a struct through, then the constructor with inout works on both lines in main above. So I guess this has something to do with reference types (As the same behaviour is exhibited if T == int*) What's the recommended way to handle this? Cheers, - Ali
Re: How to get an inout constructor working with a template wrapper
On Sunday, 22 July 2018 at 23:11:09 UTC, Ali Çehreli wrote: Without much confidence on my side, first, I think you need to make the constructor parameter inout(T) as well. Otherwise, you may be making a const(W!T) initialized with a non-const T. After that, I like the "type constructor" syntax in main_alt() below (which works) but a better approach is to use a convenience function like wrap() below: struct W(T) { T val; this(inout(T) val) inout { this.val = val; } } class C {} void main_alt() { auto a = W!C(new C); auto b = immutable W!(immutable C)(new C); } auto wrap(T)(inout T t) { return inout(W!T)(t); } void main() { auto a = wrap(new C); auto b = wrap(new immutable(C)); } Ali "taklitlerinden sakınınız" :o) Thank you Ali! That helped :) I've gotten most of it sorted out now, and the factory wrap is definitely the way to go, it also turned out that inout(T) and inout T (so inout without parens) was surprisingly different (maybe it's a bug? - to test you can remove the parens around U on line 3 in this sample: https://run.dlang.io/is/gd5oxW Also over there, line 24: auto si = wrap!(immutable int)(3); seems to be giving problems. Any ideas there? Error is: onlineapp.d(8): Error: inout on return means inout must be on a parameter as well for pure nothrow @nogc @safe inout(W!(immutable(int)))(immutable(int) t) onlineapp.d(23): Error: template instance `onlineapp.wrap!(immutable(int))` error instantiating To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason. 2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information. Cheers, - Ali
Re: How to get an inout constructor working with a template wrapper
On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote: https://run.dlang.io/is/gd5oxW Sorry wrong link! This one is correct -> https://run.dlang.io/is/azxmGN
How to avoid inout type constructor with Optional type wrapper undoing string type
Hi, I'm playing around with an Optional wrapper type. It stores a type T and a bool that defines whether a value is defined or not: struct Optional(T) { T value; bool defined = false; this(U : T)(auto ref inout(U) value) inout { this.value = value; this.defined = true; } } To facilitate it's use I have two type constructors: inout(Optional!T) some(T)(auto ref inout(T) value) { return inout(Optional!T)(value); } Optional!T no(T)() { return Optional!T(); } The above produces a problem when working with strings. Basically the type information gets slightly altered so you can't do this: auto a = [no!string, some("hello")]; You get a type mismatch: * no!string = Optional!string * some("hello") = immutable(Optional!(char[])) I've created a short code gist, so basically I'm wondering how to get it to compile without changing what's in main() https://run.dlang.io/is/BreNdZ I guess I can specialize on string type T, but this is a more general problem that can be shown with: struct S {} alias Thing = immutable S; Thing thing = S(); auto x = some(thing); auto y = no!Thing; auto arr = [x, y]; // no can do buddy Cheers, - Ali
Re: How to avoid inout type constructor with Optional type wrapper undoing string type
On Monday, 23 July 2018 at 19:02:02 UTC, Jacob Carlborg wrote: This [1] compiles the first example but not the second. [1] https://run.dlang.io/is/SJ02kP Aye it does, but it also sets T to always const which is unfortunately impractical for my use case :(
Re: How to avoid inout type constructor with Optional type wrapper undoing string type
On Monday, 23 July 2018 at 19:22:13 UTC, aliak wrote: On Monday, 23 July 2018 at 19:02:02 UTC, Jacob Carlborg wrote: This [1] compiles the first example but not the second. [1] https://run.dlang.io/is/SJ02kP Aye it does, but it also sets T to always const which is unfortunately impractical for my use case :( Ok, now I'm totally confused. Defining an extra type constructor makes everything work. I.e add a const one to the inout one: auto defined(T)(const auto ref T value) { return W!T(value); } and everything works! Can anyone say why that is?
Re: How to avoid inout type constructor with Optional type wrapper undoing string type
On Monday, 23 July 2018 at 19:31:42 UTC, aliak wrote: Ok, now I'm totally confused. Defining an extra type constructor makes everything work. I.e add a const one to the inout one: auto defined(T)(const auto ref T value) { return W!T(value); } and everything works! Can anyone say why that is? Boh, seems other problems crop up now as doing this: auto a = defined!(int*)(null); produces error: onlineapp.d(13): Error: inout constructor onlineapp.W!(int*).W.__ctor!(int*).this creates const object, not mutable onlineapp.d(30): Error: template instance `onlineapp.defined!(int*)` error instantiating https://run.dlang.io/is/BWYxA8
Re: Initialise non-copyable, non-default-constrauctable member struct
On Friday, 27 July 2018 at 12:11:37 UTC, Peter Particle wrote: Question is related to this: https://dlang.org/spec/struct.html#disable_default_construction struct S { int x; @disable this(); // Disables default construction @disable this(this); // Disable copying this(int v) { x = v; } } struct T { float y; S s; @disable this(); // Disables default construction @disable this(this); // Disable copying this(float v) { y = v; s = S(cast(int)v);// tried option 1 s.__ctor(cast(int)v); // tried option 2 } } Error: struct `S` is not copyable because it is annotated with `@disable` in both cases. Is there some way around this problem? This works on the latest dmd: struct S { int x; @disable this(); // Disables default construction @disable this(this); // Disable copying this(int v) { x = v; } } struct T { float y; S s; @disable this(); // Disables default construction @disable this(this); // Disable copying this(float v) { y = v; s = S(cast(int)v); } } void main() { auto s = T(3); } https://run.dlang.io/is/lLrUiq
Re: Initialise non-copyable, non-default-constrauctable member struct
On Friday, 27 July 2018 at 13:05:07 UTC, aliak wrote: https://run.dlang.io/is/lLrUiq Sorry: https://run.dlang.io/is/20FUoj
How come isMutable returns true for structs that cannot be modified
import std.traits: isMutable; struct S { immutable int i = 3; } pragma(msg, isMutable!S); void main() { S s; s = S(); } And is there a trait that takes the transitivity of immutability in to account? Cheers, - Ali
Re: How to get an inout constructor working with a template wrapper
On Monday, 23 July 2018 at 14:46:32 UTC, Timoses wrote: On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote: [...] Both of these seem to work (as you pointed out) // immutable(W!int) auto si = wrap!(int)(cast(immutable)3); // or wrap(cast(immutable)3); // W!(immutable(int)) auto si2 = W!(immutable int)(3); [...] I don't know why wrap!(immutable int)(3); is not working. The error message "Error: inout on return means inout must be on a parameter as well for pure nothrow @nogc @safe inout(W!(immutable(int)))(return immutable(int) t)" sounds very odd and not at all helpful, at least regarding that removing immutable from the template argument works. [...] The depths of D. Why does the following only work with "return ref"? struct W(T) { T val; this(U : T)(auto ref inout U val) inout { pragma(msg, typeof(val)); this.val = val; } } // Fails without "return ref" (escaping t warning...) auto wrap(T)(return ref inout T t) { return inout W!T(t); } class C {} void main() { immutable C ci = new immutable C; auto i = wrap(im); pragma(msg, typeof(i)); } Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases! [0]: https://forum.dlang.org/thread/hxbeektmpnmfdbvjr...@forum.dlang.org
Re: How come isMutable returns true for structs that cannot be modified
On Friday, 27 July 2018 at 14:48:06 UTC, Steven Schveighoffer wrote: On 7/27/18 9:10 AM, aliak wrote: import std.traits: isMutable; struct S { immutable int i = 3; } pragma(msg, isMutable!S); void main() { S s; s = S(); } isMutable only takes the type into account, it doesn't look to see if all the internals are mutable. It literally is this: enum bool isMutable(T) = !is(T == const) && !is(T == immutable) && !is(T == inout); And is there a trait that takes the transitivity of immutability in to account? I think you are looking for https://dlang.org/phobos/std_traits.html#isAssignable -Steve Ah! Yes I think I am. Thanks!
Re: How to get an inout constructor working with a template wrapper
On Friday, 27 July 2018 at 14:38:27 UTC, Steven Schveighoffer wrote: On 7/27/18 9:29 AM, aliak wrote: Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases! And instantiate a new template for all mutabilities. Whereas inout would only instantiate one (and disallows modification of val if not const or immutable). -Steve If you change the ctor to be inout then you get (from the link above): onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(28): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type S1 to inout(S1) onlineapp.d(44): Error: template instance `onlineapp.W!(S1).W.__ctor!(S1)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(9): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(52):instantiated from here: wrap!(C) onlineapp.d(4): Error: cannot implicitly convert expression val of type const(C) to inout(const(C)) onlineapp.d(9): Error: template instance `onlineapp.W!(const(C)).W.__ctor!(const(C))` error instantiating onlineapp.d(53):instantiated from here: wrap!(const(C)) Am I applying inout incorrectly?
Re: How to avoid inout type constructor with Optional type wrapper undoing string type
On Friday, 27 July 2018 at 14:52:20 UTC, Steven Schveighoffer wrote: On 7/23/18 2:39 PM, aliak wrote: Hi, I'm playing around with an Optional wrapper type. It stores a type T and a bool that defines whether a value is defined or not: struct Optional(T) { T value; bool defined = false; this(U : T)(auto ref inout(U) value) inout { this.value = value; this.defined = true; } } Don't use inout here. The point of inout on the constructor is to *transfer* the mutability of the parameter to the struct instance. But you want to simply copy the type into the struct (an immutable(Optional!T) is quite useless, no?) Just use U, not inout(U), and don't put inout on the constructor. -Steve But then it only works for mutable Optional right? Why would an immutable(Optional!T) be useless? Data can be "forever" empty or a certain value.
Re: How to get an inout constructor working with a template wrapper
On Friday, 27 July 2018 at 14:34:54 UTC, Steven Schveighoffer wrote: The problem here is that inout(immutable(int)) is equivalent to immutable(int). That is, all flavors of mutability are equivalent to immutable(int): /*mutable*/(immutable(int)) => immutable(int) const(immutable(int)) => immutable(int) immutable(immutable(int)) => immutable(int) So the compiler really looks at your wrap instantiation like this; inout(W!(immutable(int))) wrap(immutable(int) t) Ah ok, so the compiler remove inout behind me back here? (And then tells me it needs to be there? :p) which triggers the (really bad) message. I'd ask, why are you even worrying about explicit instantiation? Why not just wrap(3)? Just because I don't see why it should not work really. Why not allow wrap!(immutable int)(3)? or (if you really want to test it) wrap(immutable(int)(3))? To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason. Because immutable(const(int)) => immutable(int), so the compiler can't remove the inout behind your back. 2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information. Yep, do this :) Note that the point of inout is 2-fold: 1. reduce template instantiations. In fact, wrap!int works for const, mutable and immutable int. 2. ENSURE that the data isn't modified, even in the case of mutable parameters. Thanks for the explanations! For some reason it's hard to get it all to *just work* right now without the template this. But it's probably some minor detail I'm just overlooking... -Steve
Re: How to avoid inout type constructor with Optional type wrapper undoing string type
On Sunday, 29 July 2018 at 12:30:58 UTC, Steven Schveighoffer wrote: On 7/28/18 6:06 PM, aliak wrote: [...] What I meant was that string is actually mutable (the data isn't mutable, but the string can be re-assigned to another one), so Optional!string is more useful than immutable(Optional!(char[])). I shouldn't have said that immutable(Optional!T) is useless, you are right, and it wouldn't make sense for the defined flag to change there anyway. [...] Ah right. So it seems inout is removing head qualifiers on by-val parameters? Filed what I think I understood from this: https://issues.dlang.org/show_bug.cgi?id=19125
Re: How to get an inout constructor working with a template wrapper
On Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote: Am I applying inout incorrectly? No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version: Ah bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no? https://issues.dlang.org/show_bug.cgi?id=19126 Thanks, - Ali
Disabling opAssign in a type disabled all the opAssigns of an aliased type?
Is this a bug? If not is there a workaround? I would like for the alias this to function as a normal A type unless B specifically disables certain features, but it seems weird that disabling one opAssign disables all of them inside the aliases type but not in the aliasing type? struct A { void opAssign(int) {} } struct B { A a; alias a this; @disable void opAssign(float); } void main() { B b; b = 3; } Error: function `onlineapp.B.opAssign` is not callable because it is annotated with @disable Cheers, - Ali
Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?
On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote: On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote: Is this a bug? If not is there a workaround? I would like for the alias this to function as a normal A type unless B specifically disables certain features, but it seems weird that disabling one opAssign disables all of them inside the aliases type but not in the aliasing type? struct A { void opAssign(int) {} } struct B { A a; alias a this; @disable void opAssign(float); } void main() { B b; b = 3; } Error: function `onlineapp.B.opAssign` is not callable because it is annotated with @disable Cheers, - Ali What happens if you omit the @disable line? Compiles ok then.
Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?
On Monday, 30 July 2018 at 20:20:15 UTC, Alex wrote: On Monday, 30 July 2018 at 19:33:45 UTC, aliak wrote: On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote: On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote: [...] What happens if you omit the @disable line? Compiles ok then. So... is this a valid workaround? ;) Hehe. Unfortunately not. It's for a proxy type that I need to disallow assignment to. But the proxy type uses alias to a T. So if T has a custom opAssign then bye bye functionality.
Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?
On Monday, 30 July 2018 at 20:38:33 UTC, aliak wrote: On Monday, 30 July 2018 at 20:20:15 UTC, Alex wrote: On Monday, 30 July 2018 at 19:33:45 UTC, aliak wrote: On Monday, 30 July 2018 at 18:47:06 UTC, Alex wrote: On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote: [...] What happens if you omit the @disable line? Compiles ok then. So... is this a valid workaround? ;) Hehe. Unfortunately not. It's for a proxy type that I need to disallow assignment to. But the proxy type uses alias to a T. So if T has a custom opAssign then bye bye functionality. The actual code is here if you're curious: https://github.com/aliak00/optional/pull/16/commits/93d51d790d313be3b108df2bd8b3699adc898bd0 Right now I've only: @disable this(); // Do not allow user creation of a Dispatcher @disable this(this) {} // Do not allow blitting either But I also want to @disable void opAssign(U)(Dispatcher!U) So that you can't reassign to the Dispatcher (i.e. proxy type) But if I do that then the opAssigns in the Optional!T cease functioning.
Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?
On Monday, 30 July 2018 at 20:54:28 UTC, Simen Kjærås wrote: On Monday, 30 July 2018 at 18:30:16 UTC, aliak wrote: Is this a bug? If not is there a workaround? I would like for the alias this to function as a normal A type unless B specifically disables certain features, but it seems weird that disabling one opAssign disables all of them inside the aliases type but not in the aliasing type? struct A { void opAssign(int) {} } struct B { A a; alias a this; @disable void opAssign(float); } void main() { B b; b = 3; } Error: function `onlineapp.B.opAssign` is not callable because it is annotated with @disable The workaround is to not disable opAssign. :p Since this does work for other member functions that opAssign, I'm gonna say it's a bug - please file it in Bugzilla. A perhaps better workaround than the above is to wrap A's opAssigns. Sadly, this can't be done with template mixins, since they don't overload with non-mixins. It can be done with string mixins, however. It's also possible to encapsulate all this in a nice little template: struct A { void opAssign(int) {} void opAssign(float) {} } struct B { A a; alias a this; @disable void opAssign(float); mixin(wrap!(B, "opAssign")); } string wrap(T, string methodName)() { enum targetName = __traits(getAliasThis, T)[0]; return `import std.traits : Parameters, ReturnType; static foreach (e; __traits(getOverloads, typeof(`~targetName~`), "`~methodName~`")) static if (!is(typeof({static assert(__traits(isDisabled, getOverload!(typeof(this), "`~methodName~`", Parameters!e)));}))) ReturnType!e `~methodName~`(Parameters!e args) { return __traits(getMember, `~targetName~`, "`~methodName~`")(args); }`; } template getOverload(T, string name, Args...) { import std.traits : Parameters; import std.meta : AliasSeq; template impl(overloads...) { static if (overloads.length == 0) { alias impl = AliasSeq!(); } else static if (is(Parameters!(overloads[0]) == Args)) { alias impl = overloads[0]; } else { alias impl = impl!(overloads[1..$]); } } alias getOverload = impl!(__traits(getOverloads, T, name)); } unittest { B b; b = 3; static assert(!__traits(compiles, b = 3f)); } And that's enough magic for me for one night. -- Simen Heheh Amazing! In today's episode of extreme D (why is that not a thing?), we give you a "nice little template" :p https://issues.dlang.org/show_bug.cgi?id=19130 Would it take much to fix it up to use with templated opAssigns as well? I tried for a bit and got stuck with trying to get parameters and now I'm giving up for the time being. struct A { void opAssign(int) {} void opAssign()(float) {} } struct B(T) { A a; alias a this; @disable void opAssign(U)(B!U); import std.traits : Parameters, ReturnType; static foreach (t; __traits(getOverloads, A, "opAssign", true)) { static if (is(typeof(t.stringof))) { pragma(msg, t.stringof, " - ", Parameters!t); } else { pragma(msg, typeof(t), " - ", Parameters!t); } } } The Parameters!t of the template overloads all come out as "int" but only if there's the non-template opAssign(int) in A. If you remove that then you get errors. So something is fishy. Also I realized that it's just 2 opAssigns in the aliased Optional!T type for my specific use case so maybe, err... copy pasta them in. Cheers, - Ali
Re: How to get an inout constructor working with a template wrapper
On Tuesday, 31 July 2018 at 12:37:34 UTC, Steven Schveighoffer wrote: On 7/29/18 1:46 PM, aliak wrote: On Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote: Am I applying inout incorrectly? No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version: Ah bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no? It's not that there's no way, the issue is simply that you are explicitly instantiating incorrectly. wrap!int(immutable(int)(3)); -Steve Ok bear with me, but I'm really confused why "wrap!int(immutable(int)(3))" is "correct". This all seems very inconsistent: 1. wrap!(int)(3); // ok 2. wrap!(const int)(3); // ok 3. wrap!(immutable int)(3); // nope 4. wrap!(int)(3); // ok 5. wrap!(const int)(const(int)(3)); // ok 6. wrap!(immutable int)(immutable(int)(3)); // ok! So for 3, compiler sees the instantiation: inout(W!(immutable int)) wrap(immutable(int)) If I understood you correctly? But then what does it see in number 6, which works fine? And why is 2 ok if 3 is not? And finally, why can't the compiler leave the inout there and then it doesn't need to complain about it? Cheers, - Ali
Re: How to get an inout constructor working with a template wrapper
On Tuesday, 31 July 2018 at 21:54:54 UTC, Steven Schveighoffer wrote: Because inout is trying to combine all mutability modifiers into one. You want to specify the type, not the mutability, in the template parameter T. Ahhh. Ok I see... I think. This doesn't make sense. Can you post runnable code? Hehe, ok, so I fell victim to compiler generating an error for number 3 and then nothing else :p But yes you're right, if I comment out number 3 then 6 errors as well. Sorry my bad! When I go back to your original failing example, and replace the 3 with immutable(int)(3), it still fails. So for 3, compiler sees the instantiation: inout(W!(immutable int)) wrap(immutable(int)) If I understood you correctly? Yes. You can see for yourself with pragma msg: pragma(msg, typeof(t)); // immutable(int) But then what does it see in number 6, which works fine? I'm skeptical this is the case. Note that you may only see the instantiation error ONCE. Yep, you nailed that one. And why is 2 ok if 3 is not? because inout(const(T)) cannot have its inout removed. Because it may be an immutable? Or? But the complaint is really the issue. Clearly inout is specified, so it shouldn't complain that it isn't. Aye. I guess that's right. -Steve
Re: Disabling opAssign in a type disabled all the opAssigns of an aliased type?
On Tuesday, 31 July 2018 at 07:01:33 UTC, Simen Kjærås wrote: On Monday, 30 July 2018 at 23:41:09 UTC, aliak wrote: https://issues.dlang.org/show_bug.cgi?id=19130 Beautiful. :) Would it take much to fix it up to use with templated opAssigns as well? I spent half an hour doing silly things, then I came up with this: struct A { void opAssign(int) {} void opAssign(float) {} void opAssign(T)(T t) if (is(T == string)) {} } struct B { A a; alias a this; @disable void opAssign(float); mixin(wrap!(B, "opAssign")); auto opAssign(T...)(T args) if (__traits(compiles, a.opAssign(args))) { // Look ma, no magic! return a.opAssign(args); } } unittest { B b; b = "Foo!"; } (Remaining code as in my last post) Yeah, it really is that simple, since specific overloads are tried before templates. -- Simen Oh nice! So you don't even need all that mixin magic and can get away with: struct A { void opAssign(int) {} @disable void opAssign(float) {} void opAssign(T)(T t) if (is(T == string)) {} } struct B(T) { A a; alias a this; @disable void opAssign(B!T); mixin(wrap!(B, "opAssign")); } string wrap(T, string methodName)() { enum targetName = __traits(getAliasThis, T)[0]; return `auto `~methodName~`(T...)(T args) if (__traits(compiles, `~targetName~`.`~methodName~`(args))) { return `~targetName~`.`~methodName~`(args); }`; } void main() { B!int b; b = 3; b = "hello"; static assert(!__traits(compiles, { b = 3f; } )); static assert(!__traits(compiles, { b = b; } )); }
Can you tell if an template alias parameter is of a specific template?
Hi Is there a way to tell if an alias is to a template? I'm writing some algorithms and I need to distinguish between a binary predicate that provides "less than" and one that provides "equal to" semantics. So I have these two templates: template eq(alias pred) { alias eq = pred; } template lt(alias pred) { alias lt = pred; } Then in some place: static if (is(pred == eq)) { return eq(a, b); } else static if (is(pred == lt)) { return !lt(a, b) && !lt(b, a); // equality with less than predicate } else { // default assumptions about predicate } Then I can use it like: auto a = S!(eq!((a, b) => a == b)) ; auto a = S!(lt!((a, b) => a < b)); I've tried std.traits.TemplateOf and __traits(isSame and also variations of typeof and also traits.isInstanceOf. I wonder if I have to parameterize eq and lt over a compile time sequence instead? Any tips to get this working? Cheers, - Ali