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: 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: 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: 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: 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: 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 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\"'"
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: 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. :-(
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 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: 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: 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: 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: 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: 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 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 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: 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!
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: 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!
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: 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
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(, list); future.getResult(); writeln(list); > prints empty list future = vibe.core.concurrency.async(, ); 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(, list); writeln(list); }
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: 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 :)
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, ); 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: 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, ); 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.
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, ); return wait(pid); } Thanks, looks like I'll have to go that route.
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, ); return wait(currentSpawnedPid); } Any other ways to go about this? Cheers, - Ali
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; }
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: 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; }
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?
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: 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
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: 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"); }
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: 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?
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: 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.
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: 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!
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: 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.
Re: Trying to alias this a grapheme range + making it a forward range
On Monday, 8 July 2019 at 23:01:49 UTC, ag0aep6g wrote: On 08.07.19 23:55, aliak wrote: [...] `source.front` is a temporary `Grapheme` and you're calling `opSlice` on it. The documentation for `Grapheme.opSlice` warns: "Invalidates when this Grapheme leaves the scope, attempts to use it then would lead to memory corruption." [1] Ah. Right. Thanks! [...] hah yes, I realized this as well. [...] No you're right. It was indeed just making things more complicated and was just a bad idea. [...] Cheers, - Ali
Trying to alias this a grapheme range + making it a forward range
Problem 1: I'm trying to get a string to behave as a .byGrapheme range by default, but I can't figure out Grapheme. I'm trying to replicate this behavior: foreach (g; "hello".byGrapheme) { write(g[]); } In a custom type: struct ustring { string data; this(string data) { this.data = data; } auto get() { static struct Range { typeof(string.init.byGrapheme) source; bool empty() { return source.empty; } void popFront() { source.popFront; } auto front() { return source.front[]; } auto save() { return this; }; } return Range(this.data.byGrapheme); } alias get this; } But I keep on ending up with a UTFException: "Encoding an invalid code point in UTF-8" with code like: writeln("hello".ustring); Problem 2: How can I get the aliased ustring type to behave as a ForwardRange? If I add the save method to the voldermort range type, the isForwardRange!ustring fails because the requirement on isForwardRange checks to see if save returns the same type it's called on. Which is not the case here since typeof(ustring.save) == ustring.get.Range). But nontheless does have a save method. Cheers, - Ali
Re: Anyway to compare function aliases? Or any ideas?
On Thursday, 4 July 2019 at 15:22:08 UTC, Marco de Wild wrote: On Thursday, 4 July 2019 at 15:10:05 UTC, aliak wrote: [...] I don't know if it will solve your whole problem, but have you tried __traits(isSame, W0.fun, fun)? Reduced example: struct Foo(alias fun){ alias bar = fun; } void stuff(alias fun, T)(T t) { static if(__traits(isSame, fun, T.bar)) { pragma(msg, "Yes"); } else { pragma(msg, "No"); } } void a(){} void b(){} void main() { stuff!a(Foo!a()); // Yes stuff!a(Foo!b()); // No } Of course! That helps a lot yes. Thank you :) The case in the gist I pasted above works like a charm now. isSame seems like a decent enough powerhouse to get most of the practical cases it seems as well.
Anyway to compare function aliases? Or any ideas?
Any ideas on how to be able to do something like this? struct S(alias _fun) { alias Fun = _fun; } void algorithm(alias f, T)(T s) { static if ( == ) { // trivial return } else { // must perform work, then return } } Can you use function addresses in some way? I've seen that some of them are resolved to __lambda0 and other times to a function type, i.e. Error: incompatible types for (& f) is (& __lambda1): void function(A!(function () => 3) t) and int function() pure nothrow @nogc @safe That comes from doing doing this: alias g = () => 3; algorithm!g(S!g()); I've thought of something along the lines of a function alias wrapper. But I'm not sure how to make that work either. Something like: struct Fun(alias _fun, string _id) { alias Fun = _fun; enum ID = _id; } Then maybe something like: alias g = () => 3; Fun!(g, "myid") gfun; algorithm!gfun(S!gfun()); Then inside algorithm the check becomes: static if ( == ) But then I'd like to generate the ID at instantiation point. So is using __LINE__, __FILE__ and applying some hash function a good idea here? Any other ideas? Cheers, - Ali PS: If you're curious of a semi working sample, to see what I'm actually trying to do, I've put up this gist that does not compile right now: https://gist.github.com/aliak00/fcdd4fa7512035405bb7015cf6d8016f
Re: What is iota function full name
On Friday, 21 June 2019 at 09:01:17 UTC, lili wrote: Hi Guys: What is range.iota function full name That is the full name. Or what do you mean? Found on the internet somewhere: "The function is named after the integer function ⍳ from the programming language APL."
Re: Range violation error when reading from a file
On Tuesday, 18 June 2019 at 01:15:54 UTC, Samir wrote: On Monday, 17 June 2019 at 03:46:11 UTC, Norm wrote: On Monday, 17 June 2019 at 00:22:23 UTC, Samir wrote: Any suggestions on how to rectify? You could change the IF to `if(line.length > 0 && line[0] == '>')` Thanks, Norm. That seemed to do the trick and fixed the error. On Monday, 17 June 2019 at 11:25:01 UTC, aliak wrote: On Monday, 17 June 2019 at 00:22:23 UTC, Samir wrote: HOWEVER, the output is interesting. There IS a blank line between the last line and the prompt: That's because you're using write*ln*. So even though line is empty, you still output a new line. Curious. I am going to have to think about that for a bit as I don't quite understand. I mean this: $ dmd -run readfile.d 1) file.eof() == false line = "> line 1" writeln("lines 1" + \n); 2) file.eof() == false line = line 2 writeln("line 2" + \n); 3) file.eof() == false line = line 3 writeln("line 3" + \n); 4) file.eof() == false line = > line 4 writeln("> line 4" + \n); 5) file.eof() == false line = line 5 writeln("line 5" + \n); 6) file.eof() == false line = "" // empty since there're no lines left in file writeln("" + \n); <-- this is your blank line 7) file.eof() == true
Re: How does this template work?
On Monday, 17 June 2019 at 18:25:24 UTC, Robert M. Münch wrote: On 2019-06-16 15:14:37 +, rikki cattermole said: observerObject is an eponymous template. What this means (in essence) is the symbol inside the template block == template block. Hmm... ok. Is there any reason to have these "eponymous templates"? I don't see any benefit... Less typing for one. Otherwise you'd have to write: auto observer = observerObject!int.observerObject(TestObserver());
Re: Range violation error when reading from a file
On Monday, 17 June 2019 at 00:22:23 UTC, Samir wrote: Also, if I run the program below with the same file, I don't get any range violation errors: Ya, writeln will not access individual elements of a range if there aren't any. So no violations occur. HOWEVER, the output is interesting. There IS a blank line between the last line and the prompt: That's because you're using write*ln*. So even though line is empty, you still output a new line. Any suggestions on how to rectify? You can do: if (!line.length) { continue; } Inside your while loop after the call to strip.
Re: Range violation error when reading from a file
On Sunday, 16 June 2019 at 23:44:49 UTC, Samir wrote: On Sunday, 16 June 2019 at 23:03:04 UTC, aliak wrote: stripping the last line could result in an empty line if it just has strippable characters? The last line of the file is just text but without a newline (\n) character or any other whitespace character at the end. I get the same error when I remove the strip function from the readln line. http://www.cplusplus.com/reference/ios/ios/eof/ The fail bit is only set after reading fails. So after you read the last line, your eof will still return true, and hence your range violation.
Re: Range violation error when reading from a file
On Sunday, 16 June 2019 at 22:47:14 UTC, Samir wrote: I am trying to read from a text file using the following code: import std.stdio; import std.string; void main() { File file = File("test.txt"); string line; while (!file.eof()) { line = strip(file.readln()); if (line[0] == '>') { // line 10 writeln(line[1..$]); } else { writeln(line); } } } and I get the following error AFTER the last line is processed: core.exception.RangeError@readfile.d(10): Range violation ??:? _d_arrayboundsp [0x448efa] ??:? _Dmain [0x4459f7] Any idea what I am doing wrong? When processing the if statement or writing the slice, am I inadvertently trying to read a non-existent line in the file? Thanks in advance Samir stripping the last line could result in an empty line if it just has strippable characters?
Re: Is there a way to disable copying of an alias this'd member? - trying to make a NotNull type
On Friday, 24 May 2019 at 12:03:08 UTC, Simen Kjærås wrote: On Friday, 24 May 2019 at 11:40:20 UTC, aliak wrote: It's ref so that you can do this for e.g. class C { int i; } auto a = notNull!C; a.i = 3; That's a valid concern for a struct, but classes are already reference types, so you're only adding a new layer of ref-ness. The above will work great with a non-ref alias this. -- Simen Ah true. Yes I guess I can do this for ref types indeed. And maybe I can just constrain it to classes, interfaces and pointers 樂 Cheers, - Ali
Re: Is there a way to disable copying of an alias this'd member? - trying to make a NotNull type
On Friday, 24 May 2019 at 10:40:01 UTC, Simen Kjærås wrote: On Friday, 24 May 2019 at 10:16:50 UTC, aliak wrote: Basically, I want this to fail: auto notNull(T, Args...)(Args args) { return NotNull!T(new T(args)); } struct NotNull(T) { private T _value; @property ref inout(T) value() inout { return this._value; } alias value this; //disable opAssign to null as well } class C {} void func(ref C t) { t = null; } auto a = notNull!C; func(a); // i want a compile error here Any ideas that don't involve disabling copying or making the property non-ref? Pretty sure that can't be done. On the other hand, why is the property ref if you're explicitly not going to use its ref-ness? Alternatively, can you show me how you use its ref-ness? It's ref so that you can do this for e.g. class C { int i; } auto a = notNull!C; a.i = 3; I guess maybe there's a way to go about supporting that kinda thing with opDispatch. But I've tried doing that in the optional type [0] and it's rather painful to get right, and trickier to make @safe as well. And just for completeness, you are aware that alias this takes an overload set, so that this works? struct NotNull(T) { private T _value; @property inout(T) value() inout { return _value; } @property void value(T val) { _value = val; } // new alias value this; // disable opAssign to null as well } class C {} void func(ref C t) { t = null; } unittest { NotNull n; n = new C(); // Look ma, I'm assigning without ref! func(n); // Does not compile - value() doesn't return by ref } -- Simen Si si. I is aware. I've disabled opAssign to T actually (i think i have at least). And I only allow assigning to another NotNull else there's no way to guarantee that the NotNull stays non null. It looks like I'm going to have to sacrifice being able to manipulate member variables of the type the NotNull is wrapping, or give up on the guarantee of the inner value not being null. [0] https://code.dlang.org/packages/optional
Is there a way to disable copying of an alias this'd member? - trying to make a NotNull type
Basically, I want this to fail: auto notNull(T, Args...)(Args args) { return NotNull!T(new T(args)); } struct NotNull(T) { private T _value; @property ref inout(T) value() inout { return this._value; } alias value this; //disable opAssign to null as well } class C {} void func(ref C t) { t = null; } auto a = notNull!C; func(a); // i want a compile error here Any ideas that don't involve disabling copying or making the property non-ref? Full example here: https://run.dlang.io/is/ubOwkd Thanks!
Re: alias this and struct allocation
On Monday, 6 May 2019 at 14:48:56 UTC, faissaloo wrote: I've been having some memory issues (referenced objects turning to nulls for no apparent reason) and I was wondering if I've misunderstood how allocation works when instantiating a struct that uses alias this: import std.stdio; struct Parent { int a; } struct Child { Parent base; alias base this; int y; } auto myStructMaker() { return new Child(Parent(10),20); } void main() { writeln(*myStructMaker()); } In this example is the data in base guaranteed to exist? Or is base definitely part of the allocation of Child on the heap? Base exists as a value type inside Child so if Child exists, then base is definitely there. If base was a class or a pointer to a struct, then it may or may not exist. Here's an excellent post from HS Teoh that explains a lot of this: https://forum.dlang.org/post/mailman.2535.1417413189.9932.digitalmars-d-le...@puremagic.com Do you have an example of a referenced object turning to null? We may be able to spot something
Re: alias fails to compile
On Monday, 22 April 2019 at 08:02:06 UTC, Arun Chandrasekaran wrote: What am I doing wrong here? struct A { union B { int bb; } B b; alias aa = B.bb; } void main() { A a = A(); // a.b.bb = 4; // works a.aa = 4; // fails } https://run.dlang.io/is/kXaVy2 You can get the behaviour you want with opDispatch, and generalize it with a mixin template: mixin template AliasMember(string aliasName, string memberName) { ref opDispatch(string name)() if (name == aliasName) { return mixin(memberName); } } struct A { union B { int bb; } B b; mixin AliasMember!("aa", "b.bb"); } void main() { A a = A(); a.aa = 4; }
Re: alias sequences of sequences
On Sunday, 7 April 2019 at 04:58:13 UTC, Alex wrote: Is there any way to get sequences of sequences? Using RT, I have to use strings [[`string`, `0`], ...] when it would be much better to use [[string, 0], ...] Ideally it wouldn't add so much overhead that it defeats the purpose. https://aliak00.github.io/bolts/bolts/meta/AliasPack.html
Re: Why this eponymous template does not compile?
On Monday, 25 March 2019 at 09:27:03 UTC, Victor Porton wrote: /// template sychronizedMemoize(alias fun) { void sychronizedMemoize() { } } void f() { } void main() { synchronizedMemoize!f(); } /// /tmp/temp_7F3C101460D0.d(9,5): Error: template instance `synchronizedMemoize!f` template `synchronizedMemoize` is not defined, did you mean sychronizedMemoize(alias fun)()? Why the error? Is it compiler bug? DMD v2.084.1 Typo in eponymous template. syc vs sync.
Re: Can't make inout work.
On Sunday, 17 March 2019 at 20:23:44 UTC, Paul Backus wrote: On Sunday, 17 March 2019 at 10:49:03 UTC, aliak wrote: [...] For some reason, when you call `make("hello")`, the template argument T is being inferred as char[] instead of string. (You can see this by putting `pragma(msg, T)` in the body of make.) It works if you instantiate make explicitly with `make!string("hello")`. This seems like a bug to me. If you remove inout from the code, T is correctly deduced as string. https://issues.dlang.org/show_bug.cgi?id=19749
Re: Can't make inout work.
On Sunday, 17 March 2019 at 17:22:13 UTC, Kagamin wrote: struct S(T) { T value; bool opEquals(U:S!V,V)(in U r) const { return value==r.value; } } Hmm, that actually works for opEquals. But now you just hit the same problem with some other construct, unfortunately: auto x = [make("hello"), S!string("hi")]; same error.
Re: Can't make inout work.
On Saturday, 16 March 2019 at 03:49:26 UTC, Paul Backus wrote: On Friday, 15 March 2019 at 23:57:15 UTC, aliak wrote: Anyone knows how to make this work? You need an explicit `inout` on the return value of `make`: auto ref make(T)(inout auto ref T value) { return inout(S!T)(value); } Ah! Thanks! So next problem with that: import std.stdio; struct S(T) { T value; } auto make(T)(inout auto ref T val) { return inout(S!T)(val); } void main() { writeln(make("hello") == S!string("hello")); } Error: Error: incompatible types for (make("hello")) == (S("hello")): immutable(S!(char[])) and S!string I think that's just this bug (which is marked as a diagnostic for some reason): https://issues.dlang.org/show_bug.cgi?id=19126 Thoughts on any workarounds?
Can't make inout work.
This is the set up I have, and I'm not sure how to get the main function at the bottom to compile. The error in the code below is that it cannot implicitly convert an inout(C) to a C in the constructor of S(T). If you remove the constructor that takes an inout then you get a "cannot deduce function from argument types !()(inout(C))" because there's no constructor that can take in inout. If you remove the inout form the function "f", then "a.f" cannot be deduced because there's no f that takes an inout(C). If you remove the inout from the "make" function, then you get: "only parameters or stack based variables can be inout." Anyone knows how to make this work? struct S(T) { T value = T.init; } auto ref make(T)(inout auto ref T value) { return S!T(value); } auto ref f(T)(inout auto ref S!T s) { return make(s.value); } void main() { class C {} const a = S!C(); a.f; } Cheers, - Ali
Re: inout auto ref escaping a reference to parameter, only errors with vibe Json type, or if inout is there.
On Monday, 11 March 2019 at 22:29:05 UTC, aliak wrote: [...] Here's a much reduces test case: struct W(T) {} struct S { int* data; } template match1(alias handler) { auto ref match1(T)(inout auto ref W!T w) { return handler(); } } template match2(alias handler) { auto match2(T)(auto ref W!T w) { return match1!handler(w); } } void main() { W!int() .match2!(() => S()); }
Re: inout auto ref escaping a reference to parameter, only errors with vibe Json type, or if inout is there.
On Monday, 11 March 2019 at 22:29:05 UTC, aliak wrote: Hi, I have an error that says "Error: returning `match1(opt)` escapes a reference to parameter `opt`, perhaps annotate with `return`". [...] Ok, I've found out something else. It only happens when you're returning a type that has an indirection. So instead of the Json type if we returned an S type where S was: struct S { void[2] data; } We get the same error.
inout auto ref escaping a reference to parameter, only errors with vibe Json type, or if inout is there.
Hi, I have an error that says "Error: returning `match1(opt)` escapes a reference to parameter `opt`, perhaps annotate with `return`". The code is here: https://run.dlang.io/is/ESZDW4 (It's copied at the end of this post as well) 1) If you remove the inout from line 11. It works. 2) If you *do not* call match2 and call match1 instead, it also works. 3) If you return something other than vibe's Json type, it works (afaict) Am I using inout wrong? Why is it only happen with Json type so far. If I return any other random struct it works fine. And why does it work if I don't go through the "match2" template? Any help would be much appreciated. --- template match1(handlers...) { auto ref match1(T)(inout auto ref Optional!T opt) { // remove inout, it works if (opt.empty) { return handlers[1](); } else { return handlers[0](opt.front); } } } template match2(handlers...) { auto match2(T)(auto ref Optional!T opt) { return match1!handlers(opt); } } void main() { some(1) .match2!( // use match1, it works (int i) {return Json(1);}, // return anything else, it works () {return Json(1);} ) .writeln; } Cheers, - Ali
Re: Setting immutable static data inside a struct in a module constructor?
On Sunday, 3 March 2019 at 20:41:36 UTC, Alex wrote: On Sunday, 3 March 2019 at 20:10:14 UTC, aliak wrote: Is it possible to initialize static immutable members of a struct like you could do for a global immutable one? immutable string a; struct Test { static immutable string b; } shared static this() { a = "foo"; Test.b = "bar"; } Error: cannot modify immutable expression b Hmm... should work, I think... But this works in any case: immutable string a; struct Test { static immutable string b; shared static this() { b = "bar"; } } Ah, did not know that. Thank you!
Setting immutable static data inside a struct in a module constructor?
Is it possible to initialize static immutable members of a struct like you could do for a global immutable one? immutable string a; struct Test { static immutable string b; } shared static this() { a = "foo"; Test.b = "bar"; } Error: cannot modify immutable expression b
Re: Concatenating compile time sequences
On Saturday, 2 March 2019 at 02:38:09 UTC, H. S. Teoh wrote: On Sat, Mar 02, 2019 at 02:16:22AM +, Victor Porton via Digitalmars-d-learn wrote: [...] Keep in mind that sequences produced by AliasSeq are auto-expanding, meaning the above construct will automatically flatten into a flat AliasSeq!(int, "x", float, "y", double, "z"). If that's not what you want, you need to wrap your subsequences in a separate, non-eponymous template. [...] I'm not sure what "alias enum" is supposed to mean; is that a typo? Surely you mean just "alias"? [...] This line doesn't do what you think it does, because of auto-expansion. It's essentially exactly the same thing as: private alias processFields(T, name, Fields...) = AliasSeq!(T, name, processFields!(Fields)); i.e., the nested AliasSeq has no effect. [...] If you want anything that retains a nested structure, you cannot use AliasSeq because of auto-expansion. You need to define your own, non-eponymous template container, e.g.: template MySeq(T...) { alias data = T; } alias processFields(T, name, Fields...) = AliasSeq!(MySeq!(T, name), MySeq!(processFields!(Fields))); The MySeq!(...) "protect" their contents from flattening into the outer list, while the outer AliasSeq causes individual MySeq!(...)'s to be promoted to the top level sequence rather than producing a tree-like structure. Note that to access the data inside a MySeq, you'll have to use .data, for example: alias fields = processFields!(int, "x", float, "y"); alias type0 = fields[0].data[0]; // int string name0 = fields[0].data[1]; // "x" alias type1 = fields[1].data[0]; // float string name1 = fields[1].data[1]; // "y" Hope this helps. T There's a package called bolts that has an AliasPack defined that could allow you to do something like: template split(seq...) if (seq.length % 2 == 0) { static if (seq.length >= 2) { alias Pair = AliasPack!(seq[0], seq[1]); alias split = AliasSeq!(Pair, .split!(seq[2..$])); } else { alias split = AliasSeq!(); } } Running code: https://run.dlang.io/is/lfTOBz Cheers, - Ali
Re: Why is SwitchError an error and how is it unsafe to continue after catching it?
On Sunday, 24 February 2019 at 11:05:31 UTC, Alex wrote: On Sunday, 24 February 2019 at 10:53:09 UTC, aliak wrote: [...] There is a semantic difference between a switch and a final switch statement, defined here: https://dlang.org/spec/statement.html#final-switch-statement By this difference, the writer of the final switch declares, that it is unrecoverable to pass something unexpected to the switch statement. The catch of an error as you demonstrated is, therefore, a contradiction to the finality of the switch. Hmm ok. Yes that makes sense to see it that way. Thanks! I mean, if you know, that something beyond the enum can be passed, use a normal switch and handle the case in the default section. If you are able to ensure, this case is unreachable, you express this knowledge/ability by the final switch and don't need the try-catch clause at all. Aye, agreed.
Why is SwitchError an error and how is it unsafe to continue after catching it?
Because from what I understand, an Error is something you should not be catching and represents something unrecoverable. And it the docs say that it's unsafe to continue execution. But the following code is very recoverable and I don't see how it's unsafe to continue executing: import optional; import core.exception: SwitchError; enum Enum : string { one = "one", two = "two" } Optional!Enum makeEnum(string value) { try { final switch (value) { case Enum.one: return some(Enum.one); case Enum.two: return some(Enum.two); } } catch (SwitchError) { return no!Enum; } } unittest { assert(makeEnum("one") == some(Enum.one)); assert(makeEnum("huh") == no!Enum); } Cheers, - Ali
Re: Temporary @trusted scope
On Tuesday, 18 December 2018 at 13:52:29 UTC, Steven Schveighoffer wrote: On 12/18/18 6:29 AM, Simen Kjærås wrote: On Tuesday, 18 December 2018 at 10:14:50 UTC, Per Nordlöw wrote: What's the preferred way of creating a temporary @trusted scope without writing a separate function? Jonathan's idea might also be encapsulated in a function, just like assumeUnique in Phobos: import std.stdio; template unsafe(alias fn) { @trusted auto unsafe(T...)(T args) { return fn(args); } } @system void fun(int n) { writeln("foo!"); } @safe unittest { unsafe!({ fun(2); }); unsafe!fun(2); } Wow, I really like this. The only real problem is that one generally searches for @trusted when looking for unsafe code, but unsafe is pretty obvious too. Also, args should be auto ref. Only thing better I can think of (for the second example) is to define a prototype with the correct information, only with @trusted (and specify the mangle). But any decent compiler should get rid of any overhead there. -Steve I've been gathering assume related stuff like this in a lib under an "assume" template. You can generalize further with multiple attributes inside a non-eponymous thing and use them like: assume!fun.safe_(2); assume!fun.nogc_(2); I guess it's no very idiomatic D though, but I feel it reads better ... ok well maybe 路♂️: https://aliak00.github.io/bolts/bolts/assume/assume.html Easier to be more specific with searches for "assumeSafe" instead of just "assume!" though. Cheers, - Ali
Re: Tricky DMD bug, but I have no idea how to report
On Monday, 17 December 2018 at 21:59:59 UTC, JN wrote: Hey guys, while working on my game engine project, I encountered a DMD codegen bug. It occurs only when compiling in release mode, debug works. Unfortunately I am unable to minimize the code, since it's quite a bit of code, and changing the code changes the bug occurrence. Basically my faulty piece of code looks like this [...] I remember a couple of months ago someone complaining about similar issues when switching to a newer dmd. I tried looking for the thread but can’t find it. Think it was on the general list. Have you tried previous compiler versions yet?
Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue?
On Thursday, 13 December 2018 at 23:33:39 UTC, Stanislav Blinov wrote: On Thursday, 13 December 2018 at 13:17:05 UTC, aliak wrote: [...] Hypothetically, yes, e.g. an object that contains references to itself. However, D operates on the assumption that you don't have such objects. And even though it can't be statically checked, move and swap do actually perform this check at runtime in debug builds. Operating under that rule, it should be legal to move any values that are passed to you. In fact, I postulate that it *must* be done instead of making copies. Unfortunately, Phobos doesn't agree. [...] Oh cool! An isRef trait. TIL! And I see, thank you all for the tips!
Re: Can you move a disabled this(this) struct in to a container type if it's an rvalue?
On Thursday, 13 December 2018 at 12:08:22 UTC, Boris-Barboris wrote: On Thursday, 13 December 2018 at 09:51:42 UTC, aliak wrote: [...] You can just move in container constructor: struct S { @disable this(this); this(int i) {} } struct Container(T) { T value; this(T value) { import std.algorithm: move; this.value = value.move; } } void main() { auto a = Container!S(S(3)); } Ah. Is there any case where you would not want to do that when you have a T value as parameter? And, what if it's "this()(auto ref T value)"? Then moving could be dangerous if the parameter was passed as a ref. Or maybe it just wouldn't compile?
Re: Can you move a disabled this struct in to a container type if it's an rvalue?
On Wednesday, 12 December 2018 at 21:11:38 UTC, Paul Backus wrote: On Wednesday, 12 December 2018 at 20:05:18 UTC, aliak wrote: Ie: struct S { @disable this(); this(int i) {} } struct Container(T) { T value; this(auto ref T value) { this.value = value; } } void main() { auto a = Container!S(S(3)); // can't do this. } The only error I get when I compile this has to do with incorrect use of `auto ref`. If I change the constructor's signature to `this()(auto ref T value)`, it works fine. Crap! So sorry, this was supposed to be this(this) and that auto ref is not supposed to be there :( Posted new (and correct) message: https://forum.dlang.org/thread/sasdsmxmikxqfxhtb...@forum.dlang.org
Can you move a disabled this(this) struct in to a container type if it's an rvalue?
Ie: struct S { @disable this(this); this(int i) {} } struct Container(T) { T value; this(T value) { this.value = value; } } void main() { auto a = Container!S(S(3)); // can't do this. } I can build a custom constructor for Container that makes this work: static auto construct(Args...)(auto ref Args args) { import std.algorithm: move; auto value = T(args); auto opt = Container!T.init; opt.value = move(value); return move(opt); } And then "auto a = Container!T.construct(3);" works. But is there a way to do it without adding a custom constructor type? Cheers, - Ali
Can you move a disabled this struct in to a container type if it's an rvalue?
Ie: struct S { @disable this(); this(int i) {} } struct Container(T) { T value; this(auto ref T value) { this.value = value; } } void main() { auto a = Container!S(S(3)); // can't do this. } I can build a custom constructor for Container that makes this work: static auto construct(Args...)(auto ref Args args) { import std.algorithm: move; auto value = T(args); auto opt = Container!T.init; opt.value = move(value); return move(opt); } But is there a way to do it without adding a custom constructor type? Cheers, - Ali
Re: Calling function explicitly from mixin template results in recursive call instead
On Sunday, 9 December 2018 at 18:36:50 UTC, Dennis wrote: I'm using Adam's workaround from https://issues.dlang.org/show_bug.cgi?id=19365, but now I have endless recursion. Reduced code: ``` mixin template operators() { S opBinary(string op: "+")(S rhs) { return rhs; } // (A) auto opBinary(string op, T)(T rhs) if (false) { return rhs; } } struct S { mixin operators ops; S opBinary(string op, T)(T a) { return ops.opBinary!op(a); } } void main() { S.init.opBinary!"+"(S.init); } ``` Believe it or not, `ops.opBinary!op(a);` doesn't call anything from the mixin template ops, but it calls itself and it results in a stack overflow. I think this is a bug, but last time I was wrong, so maybe someone can explain what's going on here. I think the docs [0] are not as specific as they can be, but there's this part: "If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one". Later on there's a section on disambiguating between conflicting symbols, but that sections feels wanting. Furthremore, this seems to work as expected: mixin template Foo() { void f() { writeln("Foo.f"); } } mixin Foo foo; void f() { writeln("f"); foo.f; } void main() { f; } I think I'd file this and see if someone complains. Does anyone know how to get this working? Does this fix your issue? struct S { mixin operators ops; S opBinary(string op, T)(T a) { alias opBinary = ops.opBinary; // explicitly alias opBinary in this scope return opBinary!op(a); } } Cheers, - Ali [0] https://dlang.org/spec/template-mixin.html#mixin_scope
Re: How to set constant value to environment variable at compile time?
On Monday, 10 December 2018 at 11:08:23 UTC, Narxa wrote: Hello, people! I would like to have a constant with the value of some environment variable that is defined at compile time. In FreePascal, it can be done by defining it in source as: VALUE_OF_SOMETHING = {$I %SOMETHING%}; And I can call the compiler with (bash): SOMETHING='Anything' export SOMETHING; And it will automatically assign VALUE_OF_SOMETHING to 'Anything'. In GCC C compiler, the solution I found was more complicated but it worked. I had to explicitly define the environment variable when calling the compiler with: gcc -DSOMETHING=\""Anything"\" -o Now, I would like to do that with the 'dmd' compiler. I know I could possibly use 'gdc' to achieve that but I want to use the 'dmd' compiler. Is it possible to do that such a thing or through source or any other means? Thank you! I don't know if it's possible but one way to do it would be to use the -J switch and give it a config file that has contents: VAR1=Value1 VAR2=Value2 And then in source code: immutable config = import("config"); mixin(parseConfig); string parseConfig(string str) { string ret; foreach (line; str.split("\n")) { auto parts = line.split("="); ret ~= `string ` ~ parts[0] ~ ` = "` parts[2] `";`; } return ret; } You can also echo out the config file with bash or something Cheers, - Ali
Re: cannot use local f as parameter to non-global template
On Saturday, 8 December 2018 at 14:21:01 UTC, Paul Backus wrote: On Saturday, 8 December 2018 at 09:57:29 UTC, aliak wrote: This compiles fine. However, if I change the match template to: template match(handlers...) { auto match(alias f)(Holder!f holder) { return handlers[0](holder); } } Notice the template parameter of the eponymous match is an alias now, and the function parameter is typed as a Holder. The "de-sugared" version of your second `match` function looks like this: template match(handlers...) { template match(alias f) { auto match(Holder!f holder) { return handlers[0](holder); } } } Notice the second template nested inside the first. That's the "non-gloal template" the error is complaining about. Ah, that's a good way of breaking it down. But ok, so then the other version would be lowered to: template match(handlers...) { template match(T) { auto match(T holder) { return handlers[0](holder); } } } So now the second template is accessing a T, which is actually a Holder!f right? But doing that makes it "work". Even though the number of "contexts" needed to execute "handlers[0](holder)" is the same, right?
cannot use local f as parameter to non-global template
Hi, I'm wondering about why this happens in a certain situation and not another. I have the following code: struct Holder(alias fun) { alias T = typeof(fun()); T get() { return fun(); } alias get this; } template match(handlers...) { auto match(T)(T holder) { return handlers[0](holder); } } void main() { int f() { return i7 } auto value = Holder!f().match!( (int a) => f() ); } This compiles fine. However, if I change the match template to: template match(handlers...) { auto match(alias f)(Holder!f holder) { return handlers[0](holder); } } Notice the template parameter of the eponymous match is an alias now, and the function parameter is typed as a Holder. The error you get is basically because of bug 5710 [0] I guess. But I'm confused as to why the same thing doesn't then happen when using match(T) as opposed to match(alias f)? I can work around it by have a template constraint on match of course. But still curious why one version works and the other not, they both have to access the same frame+context data at the end of the day. [0]: https://issues.dlang.org/show_bug.cgi?id=5710
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Saturday, 1 December 2018 at 19:02:54 UTC, H. S. Teoh wrote: In the above contrived example, Artin's conjecture is implied by the Riemann hypothesis, so the second if statement would only run if p is initialized. But there is no way the compiler is going to be able to deduce this, especially not during compile time. So it is not possible to correctly flag p as being initialized or not when it is dereferenced. Therefore, leaving it up to the compiler to detect uninitialized variables is unreliable, and therefore any code that depends on this cannot be trusted. Code like the above could be exploited by a sufficiently sophisticated hack to make the uninitialized value of p coincide with something that will open a security hole, and the compiler would not be able to reliably warn the programmer of this problem. Uninitialized variables are *not* a good thing, contrary to what the author of the article might wish to believe. T If a compiler were to issue warnings/error for uninitialized variables. Then that example would be a compiler error. The logic would just be that not all code paths lead to an initialized variable, therefor *p++ is not guaranteed to be initialized - i.e. error. Swift takes this approach. Cheers, - Ali
Re: D is supposed to compile fast.
On Monday, 26 November 2018 at 03:09:03 UTC, Mike Parker wrote: I mean, can you think of any module in the Python/Javascript/C# standard library that simply including it will swell your program to the point it can't compile? I'm not an omnipotent master programmer, but as a professional, I can't recall ever having this situation in another library or language. Have you reached the point in D where you can't compile? I thought people had reached that point already: https://forum.dlang.org/post/mailman.3134.1517944133.9493.digitalmar...@puremagic.com I remember reading about a never ending for loop as well. Because of the way ctfe has to be handled "purely" without mutations, every change is a new allocation (but i could be remembering wrong). So just a large enough for loop because "uncompliable". And this is just time, the memory consumption is also quite large no? I think there are some caveats which are not mentioned when it comes to the fastness of the compiler. I remember last year's advent of code, I wanted to do everything at compile time, but at some point I thought, no, this small piece of code is taking way too long. Not worth it. And me mate's Go code was "consistently" fast.
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Wednesday, 21 November 2018 at 23:27:25 UTC, Alex wrote: Nice! Didn't know that... But the language is a foreign one for me. Nevertheless, from what I saw: Shouldn't it be var x: C? as an optional kind, because otherwise, I can't assign a nil to the instance, which I can do to a class instance in D... and if it is, it works in the same manner as C#, (tried this out! :) ) This is true. But then the difference is that you can't* call a method on an optional variable without first unwrapping it (which is enforced at compile time as well). * You can force unwrap it and then you'd get a segfault if it there was nothing inside the optional. But most times if you see someone force unwrapping an optional it's a code smell in swift. Comparing non-optional types from swift with classes in D is... yeah... hmm... evil ;) Hehe, maybe in a way. Was just trying to show that compilers can fix the null reference "problem" at compile time. And that flow analysis can detect initialization. And if you assume a kind which cannot be nil, then you are again with structs here... But I wondered about something different: Even if the compiler would check the existence of an assignment, the runtime information cannot be deduced, if I understand this correctly. And if so, it cannot be checked at compile time, if something is or is not null. Right? Aye. But depending on how a language is designed this problem - if you think it is one - can be dealt with. It's why swift has optionals built in to the language.
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Wednesday, 21 November 2018 at 17:46:29 UTC, Alex wrote: compiled against 4.6.1 Framework. However, of course, there is a NullReferenceException, if c happens to be null, when calling baz. So the difference is not the compiler behavior, but just the runtime behavior... How could the compiler know the state of Random anyway, before the program run. The compiler would not be able to prove that something was initialized and hence could give an error. Maybe c# doesn't do it but swift certainly does: class C { func baz() {} } func f() { var x: C if Int.random(in: 0 ..< 10) < 5 { x = C() } x.baz() } error: variable 'x' used before being initialized
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Tuesday, 20 November 2018 at 15:29:50 UTC, Kagamin wrote: On Tuesday, 20 November 2018 at 11:11:43 UTC, aliak wrote: This only applies to little scripts and unittests maybe. Not when you're writing any kind of relatively larger application that involves being run for longer or if there's more possible permutations of your state variables. Umm... if you write a larger application not knowing what is a reference type, you're into lots and lots of problems. I’m not sure I understood your point? I was saying that you don’t necessarily hit your null dereference within a couple of seconds.
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Monday, 19 November 2018 at 21:39:22 UTC, Adam D. Ruppe wrote: On Monday, 19 November 2018 at 21:23:31 UTC, Jordi Gutiérrez Hermoso wrote: What's the reasoning for allowing this? The mistake is immediately obvious when you run the program, so I just don't see it as a big deal. You lose a matter of seconds, realize the mistake, and fix it. This only applies to little scripts and unittests maybe. Not when you're writing any kind of relatively larger application that involves being run for longer or if there's more possible permutations of your state variables.
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Tuesday, 20 November 2018 at 03:24:56 UTC, Neia Neutuladh wrote: On Tue, 20 Nov 2018 00:30:44 +, Jordi Gutiérrez Hermoso wrote: On Monday, 19 November 2018 at 21:57:11 UTC, Neia Neutuladh wrote: Programmers coming from nearly any language other than C++ would find it expected and intuitive that declaring a class instance variable leaves it null. What do you think about making the syntax slightly more explicit and warn or possibly error out if you don't do it that way? The prevailing idea is that warnings are either non-problems, in which case they shouldn't be emitted, or things you really need to fix, in which case they should be errors. Things that are sometimes errors can be left to lint tools. Either SomeClass c = null; or SomeClass c = new SomeClass(); and nothing else. That would work, though it would be mildly tedious. However, the general philosophy with D is that things should be implicitly initialized to a default state equal to the `.init` property of the type. That default state can be user-defined with structs, but with other types, it is generally an 'empty' state that has well-defined semantics. For floating point values, that is NaN. For integers, it's 0. For arrays, it's a null array with length 0. For objects and pointers, it's null. Nulls/Nones are always a big gap in a language's type system. A common alternative is to have some Option/Maybe type like Rust or Haskell or D's Variant. Variant is about storing arbitrary values in the same variable. Nullable is the D2 equivalent of Option or Maybe. How about making that required to plug the null gap? That's extremely unlikely to make it into D2 and rather unlikely to make it into a putative D3. However, if you feel strongly enough about it, you can write a DIP. I've used Kotlin with its null safety, and I honestly haven't seen benefits from it. I have seen some NullPointerExceptions in slightly different places and some NullPointerExceptions instead of empty strings in log messages, but that's it. Think this would highly depend on your usecase. Having crashing mobile apps mostly leads to bad reviews because it's a UX nightmare for e.g. And with webservices it's a pain a lot of the times when it just crashes as well (analytics workers for e.g.). Kotlin's null safety stops you from this quite well as long as you don't interface with java libraries - then it's near useless because your compiler guarantees go out the window. But Swift... so far ... It's also a code review blessing. You just know for sure that this code won't crash and the object is "valid" because they've properly unwrapped a nullable. I can't even count the number of times (and I'd wager there're millions of similar commits) where I've put up a commit (during my c++ days) that says "fix crash" and the code is just "if(!ptr) { return; }" or a variant of that. Ok, sorry, I rambled a bit :p Cheers, - Ali
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Tuesday, 20 November 2018 at 00:30:44 UTC, Jordi Gutiérrez Hermoso wrote: On Monday, 19 November 2018 at 21:57:11 UTC, Neia Neutuladh wrote: [...] What do you think about making the syntax slightly more explicit and warn or possibly error out if you don't do it that way? Either SomeClass c = null; or SomeClass c = new SomeClass(); and nothing else. [...] Nulls/Nones are always a big gap in a language's type system. A common alternative is to have some Option/Maybe type like Rust or Haskell or D's Variant. How about making that required to plug the null gap? You can give optional (https://code.dlang.org/packages/optional) a try and see if that works for you.
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Saturday, 17 November 2018 at 21:56:23 UTC, Neia Neutuladh wrote: On Sat, 17 Nov 2018 21:16:13 +, aliak wrote: Could do. But it's not scalable. I'd have to comment out all the unittests that call the template function with a T that allocates inside the @nogc template (if I understood you correctly that it) I meant something like: void debugln(T...)(T args) @nogc { import std.stdio; debug(MyProject) writeln(args); } You use that function instead of writeln in your @nogc-compatible templates: void callFunc(alias func)() { debugln("about to call function!"); func(); debugln("done calling function!"); } Then I can write: @nogc: void foo() { printf("hello world\n"); } void main() { callFunc!foo(); } Aha! I misunderstood what you meant. Yes that's actually simpler that what I was doing :D Thanks!
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Saturday, 17 November 2018 at 17:48:43 UTC, Neia Neutuladh wrote: On Sat, 17 Nov 2018 13:55:24 +, aliak wrote: You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail. You can explicitly mark a templated function as @nogc. If you want your function's @nogc-ness inferred, you can pull out the debug logging into a separate function and explicitly mark it @nogc. Could do. But it's not scalable. I'd have to comment out all the unittests that call the template function with a T that allocates inside the @nogc template (if I understood you correctly that it)
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Saturday, 17 November 2018 at 13:46:00 UTC, Nicholas Wilson wrote: On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote: On Friday, 16 November 2018 at 13:21:39 UTC, Stanislav Blinov wrote: auto assumeNoGC(T)(return scope T t) @trusted { /* ... */ } Sawweet! Thanks, that made the printing possible! "scope" is const from what I understand right? It works without scope as well. So just "return T". No, `in` used to mean const scope. scope means roughly "this thing does not escape this function" e.g. assigning to global variables. Righto! Thanks!
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Saturday, 17 November 2018 at 13:43:20 UTC, Stanislav Blinov wrote: On Saturday, 17 November 2018 at 13:13:36 UTC, aliak wrote: Sawweet! Thanks, that made the printing possible! You're welcome ;) Still, try a more recent compiler. This works fine: void foo() @nogc { debug { import std.stdio; writefln("%d", 42); } } Yeah that does, but not the code I posted -> https://run.dlang.io/is/vH3cFa You can use "debug blah" to hide inside functions that are attributed, but when you have an attributed function that calls a template, attribtues of which are supposed to be inferred, it seems to fail. Maybe a bug if it's supposed to work? "scope" is const from what I understand right? It works without scope as well. So just "return T". No, "scope" means "does not escape scope", i.e. you can't assign that argument to some global. The only exception is through a return, in which case "return" also needed. Whether or not just "return" is sufficient, is a bit out there still (AFAIK), between DIP25, DIP1000 and current state of the language. "scope" was implemented for delegates for ages now, exactly to allow passing lambdas around without allocating their context on the GC heap. Aha, cool. Thanks!
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Friday, 16 November 2018 at 13:03:40 UTC, Zoadian wrote: debug { import std.stdio; writeln(args); } As mentioned in the original post, that does not work.