Re: Show dialog box for uncaught exception (Windows, lld-link)
On Sunday, 5 May 2024 at 18:28:29 UTC, SimonN wrote: My implementation for the message box is now: According to [UTF-8 Everywhere](https://utf8everywhere.org/#windows), I shouldn't use `MessageBoxA` at all. The `A` means ANSI codepages, _not_ UTF-8. My above code _will_ show garbage output when there is some non-ASCII in the exception message. Better: Convert to UTF-16 yourself and call `MessageBoxW`: version (Windows) { import core.sys.windows.windows; import std.conv; const wstring messageBody = wtext(/* ... */, "\0"); MessageBoxW(null, messageBody.ptr, null, MB_ICONERROR); throw /* ... */; } -- Simon
Re: Show dialog box for uncaught exception (Windows, lld-link)
On Sunday, 5 May 2024 at 17:15:10 UTC, Steven Schveighoffer wrote: } catch(Exception e) { visualDisplayOfException(e); throw e; } Thanks! That's practically the same pattern that I already use for logging: Try-catch near the entry point, show the message, re-throw. My implementation for the message box is now: catch (Throwable t) { import core.sys.windows.windows; const string errText = /* ... parse t ... */ MessageBoxA(null, errText.ptr, null, MB_ICONERROR); } That solves my problem. Even though I don't pass my game's window as the parent of the message box (first argument, where I pass `null`), the graphical game halts before exiting, shows the error, and users can screenshot both together. That's good. From your answer, I'll assume: There is no standardized way in the D ecosystem (e.g., by calling a DRuntime function from my usercode) to opt into displaying such a message box for uncaught exceptions. I have to call third-party APIs myself. Or is there something after all? From reading the 2019 thread [Deactivate windows MessageBox dialog on exception](https://forum.dlang.org/post/tlhjypvsaxzymccfc...@forum.dlang.org), it sounds like we should get an error box when we link with `-subsystem:windows`, and no box otherwise. -- Simon
Show dialog box for uncaught exception (Windows, lld-link)
Hi, for Windows, I link my executables with `lld-link`, whether for 32-bit and 64-bit and whether I've built with LDC or DMD. How can I generate a dialog box for uncaught exceptions that fly out of my executable's `main()`? When I linked with Optlink years ago for Windows 32-bit, it generated an error dialog box for an uncaught exception. But with `lld-link`, the exception's message lands only on stderr. I didn't see anything related in `lld-link -help`. Can I configure DRuntime in a special way at runtime? My application is a graphical game. I close stdout and stderr by passing `-subsystem:windows` to `lld-link` to suppress the extra console window. For a few fatal errors (missing required resources, can't open display, ...), I throw exceptions, log them to logfile, then re-throw them to crash. I can tell Windows users to look in the logfile, but it would be more fitting on Windows to show an error dialog box in addition to the logging. -- Simon
Re: Annotating SortedRange.empty const: Best way to auto-deduce annotations?
On Wednesday, 2 September 2020 at 21:40:59 UTC, Steven Schveighoffer wrote: What they can do is template the `this` parameter. Then if the underlying range supports calling that way, it will work, otherwise it won't. using `template this` should be compatible with the existing code I would think. Thanks! I've never looked much into template this -- at first glance, it offers what inout already offers -- but it sounds like the right tool for the job. (inout would straightaway disallow calls to mutable methods.) https://dlang.org/spec/template.html#template_this_parameter I'll experiment with it! -- Simon
Annotating SortedRange.empty const: Best way to auto-deduce annotations?
Hi, About this issue in Phobos: https://issues.dlang.org/show_bug.cgi?id=21216 SortedRange.empty should be const, .front should be inout Just adding const/inout to SortedRange's methods won't be enough; if we add const/inout here, then many other Phobos ranges need to become const/inout-correct to keep the tests passing. Before I dive deeper into annotating their methods, I would like to verify my assumptions on how template function attribute deduction works: 1) I know that templated functions deduce their own attributes on instantiation. But front()/empty() are non-templated methods within the templated struct SortedRange. Will attribute deduction happen here? 2) Is it sensible/possible to force attribute deduction by declaring empty() in SortedRange as a zero-argument template? I.e.: @property bool empty()() { return this._input.empty; } 3) Should I rather annotate the non-templated SortedRange.empty/.front manually? But with what, then? empty() should probably be const, but it's never @nogc if annotated manually, even if the wrapped range offers empty() @nogc. -- Simon
Re: Mergesort not working
On Sunday, 29 December 2019 at 11:02:34 UTC, Adnan wrote: while (arr1_idx < arr1.length && arr2_idx < arr2.length) result ~= arr1[arr1_idx] < arr2[arr2_idx] ? arr1[arr1_idx++] : arr2[arr2_idx++]; Given an array, it just returns a 1 length array. What's causing this? This loop stops as soon as arr1 _or_ arr2 are exhausted. Then, merge() will wrongly discard the remainder of the array that is not yet exhausted. The templating is good! -- Simon
Re: How does Rebindable suppress the compiler's optimizations for immutable?
Thanks for the detailed answers! Yes, I accept that immutable guarantees should be implemented only during @safe that doesn't call into @trusted. On Friday, 15 February 2019 at 18:59:36 UTC, H. S. Teoh wrote: At the very least, such [union] code should be automatically @system. Sensible. Honestly, I'm pretty sure that Rebindable technically violates the type system to do what it does. Hmm, I remember we discussed this, and I feel the same now about Rebindable. Either the spec gets extra rules for @trusted or unions, or Rebindable generates latent bugs. Think of immutable as hint for the programmer, not for the compiler. Right, if the compilers don't use it yet, I'm fine with that interpretation. It's merely strange that we have this very restrictive const/immutable that is advertized to help optimization, but then the compiler won't take advantage. Let's see how this develops in the long term, whether the spec gets clearer on the allowed optimization.
How does Rebindable suppress the compiler's optimizations for immutable?
std.typecons.Rebindable!(immutable A) is implemented as: private union { immutable(A) original; A stripped; } ...@trusted assignment operators... @property inout(immutable(A)) get() @trusted pure nothrow @nogc inout { return original; } alias get this; This conforms with the D safety spec: All access to the unsafe union goes through the @trusted get() and the trusted assignment operators. Rebindable!(immutable A) r = a1; // r.original is a1 r = a2; // r.original is a2 But the compiler may assume that immutable variables -- such as the immutable(A) original -- never change and thus may optimize code. Since immutable(A) original is assignable in the union, such optimization would produce wrong behavior: In the final line, the compiler could think that r.original is a1 without examining r.original. How does Rebindable prevent the compiler from optimizing according to immutable's rules?
Re: Why does nobody seem to think that `null` is a serious problem in D?
On Monday, 19 November 2018 at 21:23:31 UTC, Jordi Gutiérrez Hermoso wrote: When I was first playing with D, I managed to create a segfault What's the reasoning for allowing this? 100 % agree that there should be non-nullable class references, they're my main missing feature in D. Likewise, I'm astonished that only few D users wish for them. I understand that it's very hard to get @safely right, without code-flow analysis that Walter prefers to keep at minimum throughout D. I'm concerned about the clarity of usercode. I would like to ensure in my function signatures that only non-null class references are accepted as input, or that only non-null class references will be returned. All possibilities in current D have drawbacks: a) Add in/out contracts for over 90 % of the class variables? This is nasty boilerplate. b) Check all arguments for null, check all returned values for null? This is against the philosophy that null should be cost-free. Also boilerplate. c) Declare the function as if it accepts null, but segfault on receiving null? This looks like a bug in the program. Even if c) becomes a convention in the codebase, then when the function segfaults in the future, it's not clear to maintainers whether the function or the caller has the bug. I discussed some ideas in 2018-03: https://forum.dlang.org/post/epjwwtstyphqknavy...@forum.dlang.org -- Simon
Re: LDC 1.13.0-beta1
On Friday, 2 November 2018 at 21:04:13 UTC, kinke wrote: Glad to announce the first beta for LDC 1.13: * Based on D 2.083.0. * The Windows packages are now fully self-sufficient I'm late to the thank-you party, but yes, this is huge for me, too. I develop on Linux. For Windows binaries, I've run the DMD 32-bit toolchain in Wine because I've shied away from installing MSVS to create 64-bit Windows binaries. The LDC Win64 beta was a breeze to get working in Wine, looking forward to use it! -- Simon
Re: Things I found great about TypeScript that D could benefit from
On Friday, 27 April 2018 at 19:17:14 UTC, w0rp wrote: The first feature I found really useful is the --strictNullChecks option that TypeScript has. I hate null dereferencing errors with a passion, and they have been the number one source of bugs that I've seen. * Strict null checking is a winner, and you can use ordinary syntax to handle this. That's it, let me know your thoughts. Non-null class references are my #1 missing D feature. :-) When we don't have to worry about null-or-not, we have our mind free for the interesting problems. I love to peek around other languages and see how they tackle this problem. Thanks for the TS overview! You advocate automatic narrowing inside if (x != null) even over Optional types. Is it because you find automatic narrowing cleaner than Optional? Or do you simply consider automatic narrowing a worthwhile addition whether or not a language has non-null + Optional? ``` void f(Optional!T x) { if (x !is null) g(x); } void g(T x) { h(x); } void h(T x) { writeln(x.myField); } ``` With a strictly non-nullable T, you can write `g` and `h` cleanly and null-safely. Without non-nullable types, even with implicit narrowing, both `g` and `h` would need an if/get or optional dispatch, complicating their definition. -- Simon
Re: Pre-DConf Meetup on May 1
On Wednesday, 25 April 2018 at 14:13:55 UTC, Seb wrote: Our next D Munich Meetup will coincide with DConf to give our For those of you who stay at the hotel, we will be at the NH München Messe hotel at 18:00 and lead you towards the venue. Awesome, I'll attend! I'm posting here for lack of a meetup account. -- Simon
Re: Is there a strong reason for Nullable's alias get this?
On Monday, 16 April 2018 at 10:10:56 UTC, FeepingCreature wrote: Nullable!T to T is a narrowing conversion, since T cannot express the null case. Therefor, it must not be implicit. I agree with this. To even reach for a Nullable type in one's codebase incurs a cost -- the need is substantial to oughtweigh this complexity. In this situation, one will design internal interfaces both with and without Nullable. The strict typechecks (prevent assignment of Nullable!A to A) make large codebases of this kind safe to refactor. If the checks must get more verbose because Nullable isn't part of the language, but rather a library feature, that's certainly a cost to pay for reliability. But it's still better than these runtime crashes. It's sad every time code crashes at runtime with errors that other type systems easily find at compiletime. An alternative to Phobos's Nullable might be aliak's Optional? It's in the dub registry as "optional", or on github: https://github.com/aliak00/optional import optional; struct S { int i; } void main() { Optional!S s = some(S(5)); S t = s; } This produces the desired error at compiletime: source/app.d(6,11): Error: cannot implicitly convert expression s of type Optional!(S) to S. -- Simon
Re: merkle reverse
On Thursday, 5 April 2018 at 09:49:58 UTC, Seb wrote: Strings are bi-directional ranges, but they aren't random-access nor have a length chunks requires hasSlicing + hasLength: Okay, thanks for the great references. chunks/slide certainly need the length to decide which, and how many, elements to serve in the final chunk. The crucial part is now that an autodecoded string's final element can be determined in O(1) by looking at up to 4 code units from its un-decoded end, whereas its autodecoded length cannot be found in O(1). -- Simon
Re: merkle reverse
On Thursday, 5 April 2018 at 09:07:52 UTC, Seb wrote: FYI: The problem isn't chunks, but that strings aren't bi-directional ranges (hello ugly auto-decoding!). "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".byCodeUnit Thanks! Very appropriate because it's all hex digits anyway. Instead of std.experimental.all, one can also import std.utf. Initially, I wondered whether autodecoding was the issue here, but I dismissed it because the OP's example calls retro immediately on a string, which is supposedly not autodecodable as bi-directional. But I should examine retro's implementation because I remember several Phobos functions having special cases for strings (which is exactly the issue of auto-decoding). -- Simon
Re: merkle reverse
On Thursday, 5 April 2018 at 08:12:38 UTC, aerto wrote: This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4 Here's one solution with std.range.chunks. A small downside is that it needs the array allocation in the middle because chunks cannot offer the bi-directional range necessary for retro. import std.range; import std.algorithm; void main() { string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; assert (merkle.retro.equal( "b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4")); assert (merkle.chunks(2).array.retro.joiner.equal( "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a")); } -- Simon
Re: DIP in making: ProtoObject
On Wednesday, 4 April 2018 at 04:49:10 UTC, Andrei Alexandrescu wrote: This is not officially reviewable yet, but conveys the gist and could use some early feedback. Any insight will be appreciated. I'm delighted to see this DIP! Best of luck. If there is a root class, I agree that it should be empty. What are some good reasons to keep the root class? Associative arrays with immutable key classes rely on opEquals, opCmp, toHash. When a class derives from ProtoObject and an AA is declared, the compiler should statically check whether opEquals, opCmp, toHash are implemented, most likely via template/duck-typing, or maybe by interface. I feel there is no need to tailor ProtoObject towards AAs; that's good. It's popular to wrap class references in templated structs that then masquerade as class references: std.typecons.Rebindable, or aliak's Optional, or maybe something to enforce a custom restriction at runtime (reference is not null!). These templated structs rely on is(T == class), and it takes a lot of implementation code to make these structs blend in with raw class references. const, inout, opEquals, ..., many things can subtly get in the way. Covariant return types become impossible. It feels correct to disallow `a == b` entirely for a, b ProtoObjects, even though is(T == class)-templated structs will break when they forward opEquals explicitly. It would be nice to find a catch-all resolution that makes all existing is(T == class)-templates work with ProtoObject, but I doubt there will be one. -- Simon
Re: Fixing 18615, how to handle @safe/pure/nothrow test breakage due to object.opEquals?
On Wednesday, 28 March 2018 at 15:04:27 UTC, Kagamin wrote: See line 1957, attributes are not inferred. Wow, that hit my blind spot. :-O Thanks. I've moved the RebindableCommon.opEquals outside of the attributes and all tests pass, as expected. -- Simon
Fixing 18615, how to handle @safe/pure/nothrow test breakage due to object.opEquals?
Hi, I'm trying to fix Bugzilla 18615, Rebindable!A doesn't use class A's opEquals (returns a is b instead) [1]. The fix looks reasonably obvious, my code is at [2]. Most of the added lines is the unittest; the essence of the fix is: struct RebindableCommon(/* ... */) { // ... bool opEquals(ref const(typeof(this)) rhs) const { return this.original == rhs.original; } } But this breaks several existing unittests throughout Phobos because the comparison in object.d lacks @safe, @nogc, nothrow and pure. For example, unittests in systime.d fail: pure function [...]RebindableCommon[...].opEquals cannot call impure function object.opEquals nothrow function [...]RebindableCommon[...].opEquals may throw std/datetime/systime.d(9006): Error: template instance `std.typecons.Rebindable!(immutable(TimeZone))` error instantiating I'd rather not add attributes to the Rebindable.opEquals because this function sits in a templated struct RebindableCommon, where the compiler should deduce attributes automatically. But I don't want to remove correct attributes from unittests in systime.d either. Can I reasonably continue here to fix 18615? -- Simon [1] https://issues.dlang.org/show_bug.cgi?id=18615 [2] https://github.com/SimonN/phobos/commit/5a6fc6fd905b02e5ff93f2aaeaee2487fe8b38d0
Re: Optional type - how to correctly reset a wrapped immutable T
On Tuesday, 27 March 2018 at 15:28:40 UTC, jmh530 wrote: static if (isMutable!T) bag[0] = rhs; else bag = [rhs]; I like this idea. I'd even take it a step futher: When T is a pointer or class reference, then we can put the reference on the stack (instead of into the array) and handle assignments like Rebindable handles assignments -- provided that Rebindable really is 100 % safe to the outside, see my concerns from 2 posts above. In this case (static if), we won't even declare the array T[] bag, and instead implement as T value, bool isPresent. When T is a mutable value type, it goes on the stack, too. Again no array. When T is a const/immutable/inout value type, we declare the array as before and rebind on assignment with bag = [rhs], as you proposed here. -- Simon
Re: Optional type - how to correctly reset a wrapped immutable T
On Monday, 26 March 2018 at 14:17:03 UTC, Jonathan M Davis wrote: Rebindable does is pretty questionable as far as the type system goes, but it does what it does by forcing pointer semantics on a class reference, so the point is arguable. Yeah, I've always assumed that Rebindable cannot be implemented without internally breaking the type system, then exposing a safe interface. But this sparked my interest, I've dug out the Rebindable code: private mixin template RebindableCommon(T, U, alias This) if (is(T == class) || is(T == interface) || isAssociativeArray!T) { private union { T original; // e.g., immutable(A) for classs A U stripped; // the unqualified type, e.g., A } // ... } Does Rebindable-using code, oblivious of the hacks inside Rebindable, remain 100 % safe even with aggressive compiler optimizations? For class A, inside Rebindable!(immutable A), there is a union of (immutable A) and A. I suspect that the D compiler is allowed to treat this reference to (immutable A) as immutable itself. Have there never been bugs here when, later, stripped = another.stripped;? -- Simon
Re: #dbugfix 17592
On Wednesday, 21 March 2018 at 13:55:16 UTC, Adam D. Ruppe wrote: `emplace` is ALREADY `@nogc` Interesting -- I checked the phobos source, and none of the `emplace` or `emplaceRef` are declared `@nogc`, yet the unittests marked as `@nogc` pass. Does the compiler infer nogc-ness of `emplace` at instantiation? class A { @nogc ~this() {} } class B : A { ~this() {} } My first hunch was that B's yes-gc-destructor should be illegal when A's descructor is `@nogc`, but it can be legal because destructors in a hierarchy are chained, not overridden. Seems like there is no way to ensure at child-class-compile-time that all child classes of A must be designed `@nogc`. -- Simon
Re: Opt-in non-null class references?
On Sunday, 11 March 2018 at 09:28:39 UTC, aliak wrote: Does this maybe boil down to if two templates should be covariant on their parameter types? I'm not sure if this is always good. I haven't thought about it deeply, but I assume that some templated functions should be contravariant, and that there is no catch-all rule. inference, in theory Rebindable!(const Derived) can be completely different than Rebindable(const Base). So are covariant return types even possible I wonder? I don't think covariant return types will work here with the 2018-03 language spec. We're returning structs (Rebindable!Something) and covariant return types is specifically for classes. :-) It's one of the reasons why I shun wrapping types unless the benefit is really big. If D had implicit conversions then types can specifically say that they explicitly allow behavior like this where it made sense though. Yeah -- it shifts another burden of implementation to library type authors, I'm not sure if this path should be followed, especially since implicit constructor calls are shunned in D. (I have no opinion whether C++'s implicit constructor calls are handy enough for the obscured program flow.) * * * Here's another example where wrapped class references fail: You can override opEquals in the class, and the struct's opEquals need not necessarily call that. import std.stdio; import std.typecons; class C { int x; override bool opEquals(Object rhsObj) { const(C) rhs = cast(const(C)) rhsObj; return this.x == rhs.x; } } void main() { C a = new C(); C b = new C(); assert (a == b); // OK: Even though a !is b, we overrode opEquals // and compare a.x == b.x, which is true (0 == 0). Rebindable!(const(C)) ca = a; Rebindable!(const(C)) cb = b; assert (ca == cb); // Fails! struct Rebindable doesn't forward its // opEquals to the class's opEquals! } If this is by design, then it's very surprising. I've reported this as a bug to get a judgement from the Phobos authors: https://issues.dlang.org/show_bug.cgi?id=18615 -- Simon
Re: Article: Why Const Sucks
On Monday, 5 March 2018 at 10:57:35 UTC, Jonathan M Davis wrote: Here's something I wrote up on const: Excellent read! I enjoyed the history of proposed solutions. I've run into the trouble with annotated opEquals in classes several times. I believe an empty/nonexistant Object class is the correct solution, together with templates. If it breaks tricky opEquals-overriding usercode, then so be it. The const trouble is merely a symptom here, the real problem is Object. In structs, all const members feel alien, they preventing all copying. This seems far harder to solve. -- Simon
Re: Opt-in non-null class references?
On Sunday, 4 March 2018 at 12:03:32 UTC, aliak wrote: Maybe this part can be fixed with: struct NonNull(T) if (isPointer!T || is(T == class)) { @disable opAssign(V)(V v) {} // no no no void opAssign(V)(NonNull!V other) { // only this allowed. Interesting approach -- I'll keep it on the backburner for testing. Converting a class-heavy codebase to this would be daunting, but I don't want to rule it out yet. Wrapping class references in structs is costly, we lose a lot Can you provide an example case here? Automatic subtype detection will fail, and, thus, e.g., covariant return types. To make it clearer that this isn't a bug in Optional, but rather an artifact of D's subtype detection, I will give examples with std.typecons.Rebindable instead of with Optional. For a class A, Rebindable!(const(A)) is designed as a reference to const(A) that can be rebound to point to a different const(A). I believe Rebindable!A aliases itself away and thus Rebindable!A will not be discussed, only Rebindable!(const(A)). import std.typecons; class Base { } class Derived : Base { } static assert(is(const(Derived) : const(Base))); // OK static assert(is(Rebindable!(const(Derived)) : Rebindable!(const(Base; // fails Covariant return types will also fail. The following example doesn't compile, but would if we stripped all `rebindable' and all `Rebindable!': import std.typecons; class Base { Rebindable!(const(Base)) create() { return rebindable(new Base()); } } class Derived : Base { override Rebindable!(const(Derived)) create() { return rebindable(new Derived()); } } Speculation: There may be problems once we try to wrap class references in two different structs. We might want Optional or NonNull, and then another wrapper (e.g., Rebindable) for some other benefit. When these wrappers are written with if-constraints to take only raw D class references, we may pick only one wrapper. But I haven't investigated this yet. -- Simon
Re: Opt-in non-null class references?
On Saturday, 3 March 2018 at 18:28:42 UTC, aliak wrote: struct NonNull(T) if (isPointer!T || is(T == class)) { T value; alias value this; this(Args...)(Args args) { this.value = new T(args); } // always force creation } The pitfall here is that all structs must be default-constructible, and then all of the fields have the static init value: class A { this(int) { } } void main() { NonNull!A a; assert (a.value is null); } ...compiles and passes. Wrapping class references in structs is costly, we lose a lot of automatic conversions across subclasses, const/immutable, ... For the over 90 % of references where null is a bug (sign of forgotten assignment), it will be convenient to keep D's references. A library solution must be super-convenient to be worthwhile here. For weeks, I've put off re-discussing non-null refs directly in D because a language change is a last resort. I'm going to experiment with moving Optional's methods out If you know of other ways though I'm all ears :) No ideas for now, but I'll certainly follow this development closely, and will be happy to test things! -- Simon
Re: Opt-in non-null class references?
On Thursday, 1 March 2018 at 16:37:02 UTC, aliak wrote: I've put up a little experiment If you're interested: https://github.com/aliak00/optional Nice! Optional is like std's Nullable with extra bells and whistles to make it as painless as you can offer it. I've read all of Optional's source, skimming the dispatching introspection magic, and it's a concise wrapper that is as transparent as it can get. I can envision using this Optional type whenever I want nullable class reference, and use normal D class references as non-nullable references together with a codebase-wide rule that assigning null to normal D references is always a bug. Even the generated compiler error messages are good: Optional!C x = some(new C()); int y = x; // Error: Cannot implicitly convert from Optional!C to C. a.dispatch.i; // not ideal, but is at least safe no op. Hah, I've toyed with some examples, and this stuck out as verbose because everything else was really smooth. Optional!int dispatches wonderfully without extra syntax, whereas class C {}; Optional!C needs the extra dispatch before calling methods. -- Simon
Re: Opt-in non-null class references?
On Wednesday, 28 February 2018 at 15:29:17 UTC, Mike Franklin wrote: You might be interested in this little experiment: https://github.com/dlang/dmd/pull/7375 Indeed, this looks extremely useful, at the very least in a linter. I probably rely on ints getting initialized to 0 throughout the program, and only rarely make that explicit. With null references, the problem is not forgetting the initialization; it's expressing the intent of the variable. Usually, I want the non-null, but sometimes, I want a nullable reference and would like to require the using code to test the reference for null. Merely verifying for initialization doesn't help here; it may well be intended that null will be assigned later to the reference. -- Simon
Re: Opt-in non-null class references?
On Wednesday, 28 February 2018 at 14:05:19 UTC, Jonathan M Davis wrote: I expect that pretty much anything you propose that requires code flow analysis is DOA. Walter was arguing against precisely because code-flow analysis is so hard to get right, Thanks, that's an important judgement. I've read the 3 threads that I found around this issue, but didn't notice this sentiment before that code-flow analysis is so problematic. Yeah, non-null class fields hinge on code-flow analysis. And I'll accept that pushing non-null refs won't lead to anything if the necessary code-flow analysis is too tricky for the benefit. I've never understood why some folks have so many problems with null pointers. My gripe is that the necessarily-nullable class reference doesn't express the intent. Either a codebase must rely on silent conventions or every function with asserts. and that blows up quite quickly such that it's fixed quite quickly. Yeah, I admit that most null crashes surface adequately quickly even when you have to run the program first. It's merely sad to see D, with all its powerful static inspection, rely on runtime tests for nulls while other languages (Kotlin, Zig, and 2017 C#) rule null out at compile-time, as if it's the most natural thing in the world. -- Simon
Opt-in non-null class references?
Hi, Andrei said in 2014 that not-null-references should be the priority of 2014's language design, with consideration to make not-null the default. In case the code breakage is too high, this can be an opt-in compiler flag. Discussion here: https://forum.dlang.org/post/lcq2il$2emp$1...@digitalmars.com Everybody in the 2014 thread was hyped, but has anything ever happened in the language? In November 2017, the D forum discussed C#'s non-null warnings. Has anybody thought about this again since? In D, to prevent immense breakage, non-nullable class references need to be opt-in. I would love to see them and don't mind adapting my 25,000-line D-using project during a weekend. Are there any counter-arguments to why non-nullable references/pointers haven't made it into D yet? Feel free to attack my answers below. * * * Argument: If A denotes non-null reference to class A, it can't have an init value. Answer: Both A?.init and A.init shall be null, then use code-flow analysis. This would match D's immutable: In a class constructor, you may assign the value 5 to a field of type immutable(int) that has init value 0. The compiler is happy as long as it can prove that we never write a second time during this constructor, and that we never read before the first assignment. Likewise, it should be legal to assign from A to another A expression such as new A(), and the compiler is happy as long as the reference is assigned eventually, and if the reference is never read before assignment. (I haven't contributed to the compiler, I can't testify it's that easy.) To allow hacks, it should remain legal to cast A? (nullable reference) to A (non-nullable). This should pass compilation (because casting takes all responsibility from the compiler) and then segfault at runtime, like any null dereference today. * * * Argument: I shall express non-null with contracts. Answer: That's indeed the best solution without any language change. But it's bloaty and doesn't check anything at compile-time. class A { } void f1(A a) in { assert(a); } do { f2(a); } void f2(A a) in { assert(a); } do { f3(a); } void f3(A a) in { assert(a); } do { ...; } void g(A a) { if (a) ...; else ...; } Sturdy D code must look like this today. Some functions handle the nulls, others request non-null refs from their callers. The function signature should express this, and a contract is part of the signature. But several maintenance problems arise from non-null via contract. First issue: We now rely on unit-testing to ensure our types are correct. You would do that in dynamic languages where the type system can't give you meaningful diagonstic errors otherwise. I'd rather not fall back to this in D. It's easy to forget such tests, coverage analysis doesn't help here. Second issue: Introducing new fields requires updating all methods that uses the fields. This isn't necessarily only the methods in the class. If you have this code: class B { A a1; void f1() in { assert(a1); } do { ... } void f2() in { assert(a1); } do { ... } } When you introduce more fields, you must update every method. This is bug-prone; we have final-switch (a full-blown language feature) just to solve similar issues: class B { A a1; A a2; void f1() in { assert(a1); assert(a2); } do { ... } void f2() in { assert(a1); /+ forgot +/ } do { ... } } Third issue: Most references in a program aren't null. Especially class references that are fields of another class are often initialized in the constructor once, and never re-set. This is the predominant use of references. In D, the default, implicit case should do the Right Thing; it's fine when nonstandard features (allowing null) are explicit. Assuming that A means non-null A, I would love this instead: class A { } void f1(A a) { f2(a); } void f2(A a) { f3(a); } void f3(A a) { ...; } void g(A? a) { if (a) ...; else ...; } Or: void g(A @nullable a) { if (a) ...; else ...; } Code-flow analysis can already statically check that we initialize immutable values only once. Likewise, it should check that we only pass A? to f1 after we have tested it for non-null, and that we only call methods on A? after checking for its non-null-ness (and the type of `a' inside the `if' block should probably still be A?, not A.) * * * Argument: null refs aren't a problem, they're memory-safe. Answer: Memory-safety is not the concern here. Readability of code is, and preventing at compiletime what safely explodes at runtime. * * * Argument: Roll your own non-null type as a wrapper around D's nullable class reference. Answer: That will look ugly, is an abstraction inversion, and checks at runtime only. class A { } struct NotNull(T) if (is(T == class)) { T payload; @disable this(); this(T t) { assert(t !is
Re: String Type Usage. String vs DString vs WString
On Monday, 15 January 2018 at 14:44:46 UTC, Adam D. Ruppe wrote: On Monday, 15 January 2018 at 06:18:27 UTC, SimonN wrote: D's foreach [...] will autodecode and silently iterate over dchar, not char, even when the input is string That's not true. foreach will only decode on demand: foreach(c; s) { /* c is a char here, it goes over bytes */ } Thanks for the correction! Surprised I got foreach(c, s) wrong, its non-decoding iteration is even the prominent example in TDPL. Even `each`, the template function that implements a foreach, still infers as char: "aä".each!writeln; // prints a plus two broken characters Only `map` When I wrote "D's ranges", I meant Phobos's range-producing templates; a range itself is again encoding-agnostic.
Re: String Type Usage. String vs DString vs WString
On Monday, 15 January 2018 at 02:05:32 UTC, Chris P wrote: Is usage of one type over the others encouraged? I would use string (UTF-8) throughout the program, but there seems to be no style guideline for this. Keep in mind two gotchas: D's foreach and D's ranges will autodecode and silently iterate over dchar, not char, even when the input is string, not dstring. (It's also possible to explicitly decode strings, see std.utf and std.uni.) If you call into the Windows API, some functions require extra care if everything in your program is UTF-8. But I still agree with the approach to keep everything as string in your program, and then wrap the Windows API calls, as the UTF-8 Everywhere manifesto suggests: http://utf8everywhere.org/ -- Simon
Re: Dscanner: intentionally unused variable
On Sunday, 7 January 2018 at 00:18:27 UTC, Ivan Trombley wrote: While working with SDL, I found that I kept using the same pattern over and over: - Get the current clip rectangle. - Set a new clip rectangle. - restore the old clip rectangle on scope (exit). Instead of writing that code again and again, I wrote a simple function that returns a struct which restores the old clip rectangle in it's destructor. This works great but now dscanner complains about the variable being unused. Is there a way tell dscanner that a variable is intentionally unused? Another way would be to have the RAII wrapper in a with statement, but it produces extra indentation, which you might not like: with (MyStruct(100, 200)) { // code that uses the new clip rectangle } -- Simon
Re: Pass D const pointer to opaque C library: Guarantees? Optimization-safe?
On Saturday, 16 December 2017 at 11:19:36 UTC, Mike Parker wrote: that's a binding, not a wrapper. Right! Not sure what you mean by "safe" you only want to prevent changes on the D side and don't care if they happen on the C side, then that's fine. This, yes. I'd like const-annotated D code because of the static checks, without risking bugs from aggressive compiler assumptions. It's fine it the C side mutates privately. I am ready to take responsibility in case I misjudge whether one of the C functions mutates detectable state or not. Question 2. If yes, can the wrapper sanely declare foo(const A*) instead of foo(A*)? if you pass immutable variables to the function -- if the parameter is const even when the function modifies the variable, D will allow immutable to be passed and you're looking at unexpected behavior. This is the heart of the problem, I've overlooked this. None of my A are immutable, but declaring the bindings as foo(const A*) would take immutables. I would expect SiegeLord to reject such a PR. Only add const to parameters in C function declarations if the C API actually declares those parameters as const. That was my hunch, too. I've asked upstream on the Allegro forums. It would be a drastic change, I'd wager there won't be any const in the API anytime soon. But I'll give them the due time to decide. If no const C API, I'd stick to private wrappers around DAllegro5, with a codebase-wide rule to not pass immutable. In principle, I disagree with him how much weight should be assigned to "probably". Hmm, SiegeLord is a core Allegro 5 developer, he could judge overriding the C API's promises. But I share your sentiment that the public C API should have the final word. Many thanks for the high-quality answer! -- Simon
Pass D const pointer to opaque C library: Guarantees? Optimization-safe?
Hi, I'm calling a C library through a D wrapper. The situation is like this: C library has: struct A { ... }; A* create_a() { ... } void foo(A*) { ... } D wrapper declares: extern (C) { struct A {} A* create_a(); void foo(A*); } My D usercode: const A* a = create_a(); foo(cast(A*) a); We know that const is transitive in D and the compiler may optimize around it. If we cast away const, it's our responsibility that, e.g., the optimized caching from const will not cause bugs. The memory of the A is allocated by the C library. All the D code ever sees is a pointer, an opaque handle to the resource. How will the compiler optimizations behave around this: Question 1. Is that cast still safe in usercode if foo(a) changes some internal values in *a that are undetectable through the C API? Question 2. If yes, can the wrapper sanely declare foo(const A*) instead of foo(A*)? My use case: My const-heavy D usercode calls Allegro 5, a C game/multimedia library without any const in its API, through the D bindings DAllegro5. I'm considering to make a PR implementing question 2. Github issue: https://github.com/SiegeLord/DAllegro5/issues/42 -- Simon
Re: Sort in return statement
On Saturday, 9 December 2017 at 03:24:52 UTC, codephantom wrote: On Saturday, 9 December 2017 at 02:45:35 UTC, rjframe wrote: `sort` returns a SortedRange of ushorts, not an array of ushorts. Make it: ``` import std.array : array; return sort(numbers.take(8)).array; ``` --Ryan That's it! Thanks Ryan. Yes, this works, and your algorithm would even accept arbitary random-access ranges, not merely arrays. But since we start explicitly with a ushort[] that this function has allocated just for this algorithm, we could save the extra allocation by the final call to array(). // ushort[] numbers = ... randomShuffle(numbers); import std.algorithm.sorting : sort; numbers = numbers[0 .. 8]; sort(numbers); return numbers; sort(numbers) does two things: (1) affect the underlying data, (2) return an input range with extra information that this returned range is sorted. But in our example, we don't need to allocate a fresh array from (2). We can return the sorted data from (1), this is already in array-form. -- Simon
Re: Always std.utf.validate, or rely on exceptions?
ketmar wrote: i'd say: "ALWAYS validate before ANY further processing". On Thursday, 2 March 2017 at 17:03:01 UTC, Kagamin wrote: If you expect file with malformed utf that can cause you trouble and want to handle it gracefully, pass its content through validator and catch exception from validator. Thanks. Now, I still call std.stdio.byLine or std.stdio.lines on the raw data, this seems robust with random binary blobs. Then, I validate each line before calling anything else. -- Simon
Always std.utf.validate, or rely on exceptions?
Many functions in std.utf throw UTFException when we pass them malformed UTF, and many functions in std.string throw StringException. From this, I developed a habit of reading user files like so, hoping that it traps all malformed UTF: try { // call D standard lib on string from file } catch (Exception e) { // treat file as bogus // log e.msg } But std.string.stripRight!string calls std.utf.codeLength, which doesn't ever throw on malformed UTF, but asserts false on errors: ubyte codeLength(C)(dchar c) @safe pure nothrow @nogc if (isSomeChar!C) { static if (C.sizeof == 1) { if (c <= 0x7F) return 1; if (c <= 0x7FF) return 2; if (c <= 0x) return 3; if (c <= 0x10) return 4; assert(false); } // ... } Apparently, once my code calls stripRight, I should be sure that this string contains only well-formed UTF. Right now, my code doesn't guarantee that. Should I always validate text from files manually with std.utf.validate? Or should I memorize which functions throw, then validate manually whenever I call the non-throwing UTF functions? What is the pattern behind what throws and what asserts false? -- Simon
Re: A public domain game written in D
On Saturday, 4 February 2017 at 16:29:05 UTC, Dukc wrote: On Saturday, 4 February 2017 at 04:03:08 UTC, SimonN wrote: I've deferred my announcement to the D community because multiplayer is still WIP. I hope I didn't spoil the surprise. I thought that because it's public on GH you don't mind someone mention it. Anyway, interesting. My favorite language being used to remake one of my favorite games. No hard feelings! It's deliberately public, I want Lix discoverable by explicit searches for Lemmings-related projects. I'm glad you found it mature enough for a posting here. -- Simon
Re: A public domain game written in D
On Saturday, 4 February 2017 at 08:50:42 UTC, Stefan Koch wrote: you need to make enums into static immmutable. If you ever worked for you when using enums you were living dangerously. I've pushed a fix by moved the code to runtime, the static asserts to unittested asserts. Thanks for your hint still; will keep in mind for the future. The problematic code was like this: class A { /* ... */ } struct B { A a; /* ... */ } enum B errorsNowDuringCTFE = /* ... */; I wrote this over a year ago, trying to find out just how much can be forced into CTFE. The compiler accepted it, and yeah, it worked cross-platform. I imagined that 'enum' and 'static immutable' were equivalent, even though that looked like a stretch. Keep up the good, aggressive compiler development that finds such latent bugs! -- Simon
Re: A public domain game written in D
On Friday, 3 February 2017 at 21:14:48 UTC, Dukc wrote: http://lixgame.com/ A public domain game very much like Lemmings. I'm almost sure some of you here have played Lemmings. NOTE: I have not made or even contributed to that project. I just stumbled upon it when surfing the net and thought you may be interested to hear. Hi, I'm the author, ask me anything. :-) Lix is a Lemmings-like game with working singleplayer, but I'm still porting the networked multiplayer. I've deferred my announcement to the D community because multiplayer is still WIP. With dmd 2.073, Lix doesn't compile because CTFE can't initialize classes/struct pointers anymore. I'm working on this. Lix builds with 2.072 and earlier. -- Simon
Re: Bug after update to 2.072?
I'm not sure how to pass arbitrary dustmite arguments through dub to dustmite. `dub dustmite -h' lists arguments. When dustmite reduces your project to the empty project, maybe try this from the dustmite website: "You can also surround code that is not to be removed around the magic words DustMiteNoRemoveStart and DustMiteNoRemoveStop. Note that if you place them in comments, you won't be able to use --strip-comments." On Sunday, 6 November 2016 at 06:28:32 UTC, Alex wrote: object.Exception@DustMite/dustmite.d(270): Initial test fails (try using --no-redirect for details) This means that dustmite doesn't recognize the unreduced source as buggy. As a sanity test, dustmite runs the given test on the unreduced project, and requires this test to succeed. -- Simon
Re: immutable class can't override opEquals, workaround?
On Sunday, 21 February 2016 at 07:58:42 UTC, Jonathan M Davis wrote: opEquals still works with const and immutable if it's legal to use a class as the key in an AA, it's a bug have a working version of the PR hasn't even been looked at yet from what I can tell, and it's the simplest of the bits that need to be done Thanks for the detailed overview. Judging from the source comment at hack-casting const to mutable, naive improvements affect much more code than I have imagined. The problem and possible solutions are on the radar still, that's satisfying. I understand if it takes more time, even if I too deem it important. -- Simon
immutable class can't override opEquals, workaround?
Hi, immutable class A { int i; this(int arg) { i = arg; } override bool opEquals(Object rhsObj) { auto rhs = cast (immutable(A)) rhsObj; return rhs && i == rhs.i; } } Error by dmd 2.070: ./immutclass.d(4): Error: function immutclass.A.opEquals does not override any function, did you mean to override 'object.Object.opEquals'? My understandings: 1. immutable class A means: All methods have immutable tacked on them implicitly. 2. Object.opEquals doesn't have immutable tacked on it. If I want to override Object.opEquals, I should override without 'immutable'. 3. Overriding opEquals and toHash are necessary to make A behave properly as AA key type. This is incompatible with (2) in an immutable class. 4. I found this thread: How to turn an inout(Object) into a string http://forum.dlang.org/thread/dcobmtogyrmnaqnqy...@forum.dlang.org that I interpret as: The need for the currently-impossible override is acknowledged, but the implementation would bring significant changes to the language, therefore the solution is postponed. The above thread was from mid-2015, but I guess it's still relevant. My workaround is: Make class _A private, and declare every method immutable, except for what Object decrees to be mutable/const/... Then make a public alias A = immutable(_A). Is there something better than this? Has there been any new development on Object method removal? Jonathan M Davis has been pushing this hard 2 years ago, I'd love to see the efforts make it into the language. :-) -- Simon
Re: chain(const(array of class)) fails
On Tuesday, 2 February 2016 at 10:58:35 UTC, Marc Schütz wrote: The constraint that fails is the one with `CommonType`: `CommonType` uses the `?:` operator to derive the common type: I filed a bug report: https://issues.dlang.org/show_bug.cgi?id=15638 Interesting reduced case, so it wasn't chain after all. Thanks for filing the issue already; also thanks to Nic for good test cases. I think Adam D. Ruppe wanted to push more informative template errors -- they'd come in handy. :-) -- Simon
Re: chain(const(array of class)) fails
Sorry for late reply -- but I got around to test a couple more cases! On Monday, 1 February 2016 at 00:19:44 UTC, Nicholas Wilson wrote: Unqaul means remove any const or immutable torn the type Okay, that sounds like our 'const' shouldn't matter. 'const' is the outermost qualifier, and stripping that leaves us with B[] and C[], which were chainable earlier. StaticMap is like a compile time map What this error message says is that there is one candidate function that matches what you are attempting to do. and that chain takes a variadic argument and each of those arguments must 1) when unqualified be an input range (Basically you can foreach over it) Yep, const(B[]) and const(C[]) can be foreached. My workaround has been to replace chain() with several foreaches. 2) that the common type of the element type of the unqualified variadic argument types is not void (in this case not arrays of void) Have you tried changing The declaration of a and b to const(A[])? Surprisingly, this compiles and gives the desired output: const(B[]) b = [ new B(), new B() ]; const(A[]) c = [ new C(), new C() ]; // A instead of C chain(b, c).each!(a => a.val.writeln); With two arguments, const(array) has worked iff at least one range is of the base type. Only if none were of the base type, I got the error. Apparently, the template is smart enough to infer the common base type without 'const', but needs to be fed the basetype in case of 'const'. My gut feeling is that I should report this as a bug against phobos... Also have you tried with other reference type (e.g. assoc arrays pointers)? immutable(B[int]) b; immutable(C[int]) c; chain(b.byValue, c.byValue).each!(a => a.val.writeln); Error is the same as for the classes: template std.range.chain cannot deduce function from argument types !()(Result, Result), candidates are: /* snip */ To get this error, again, if at least one range is 'immutable(A[int]).byValue', i.e., using the base class A, the template instantiates with no problems. -- Simon
chain(const(array of class)) fails
Hi, we start with the following code snippet, which works. import std.algorithm; import std.range; import std.stdio; class A { int val; } class B : A { this() { val = 3; } } class C : A { this() { val = 4; } } B[] b = [new B(), new B()]; C[] c = [new C(), new C()]; void main() { chain(b, c).each!(a => a.val.writeln); } The output, as expected, is: 3 3 4 4 Now I change the declarations of B[] b and C[] c to the following, keeping everything else in the code snippet the same: const(B[]) b = [new B(), new B()]; const(C[]) c = [new C(), new C()]; This makes dmd 2.070 choke: ( http://dpaste.dzfl.pl/eee69fd03dd9 ) Error: template std.range.chain cannot deduce function from argument types !()(const(B[]), const(C[])), candidates are: /opt/compilers/dmd2/include/std/range/package.d(804): std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 && allSatisfy!(iseputRange, staticMap!(Unqual, Ranges)) && !is(CommonType!( staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void)) What's stumping me -- constness doesn't make dmd choke on ranges of numbers. If I replace the classes B and C with simple 'int' and 'double', this compiles again: const(int[])b = [1, 2]; const(double[]) c = [3.3, 4.4]; void main() { chain(b, c).each!(a => a.writeln); } Why does it fail for const(array of class)? Is any template magic about Unqual or staticMap relevant here? -- Simon
Re: @property not available for classes?
On Friday, 1 January 2016 at 10:14:58 UTC, Shriramana Sharma wrote: auto p = TimeSpan(1, 2); Error: no property 'opCall' for type '.TimeSpan' The error should be in 'auto p = ...', not in the line using the property. Instantiate with 'new TimeSpan(1, 2)' instead of 'TimeSpan(1, 2)'. The latter would be the constructor call for a struct. Classes go on the GC'ed heap by default. The property syntax should work. :-) -- Simon
Re: Variable below zero but if statement doesn't grab?
On Sunday, 27 December 2015 at 16:41:10 UTC, TheDGuy wrote: It looks like the debugger is not working correctly because i changed the code to this: [...] and the same problem appears. I can't watch youtube here. What numbers does your input generate? Which 'if' doesn't fire? What results would you like instead? -- Simon
Re: Variable below zero but if statement doesn't grab?
On Sunday, 27 December 2015 at 16:01:37 UTC, TheDGuy wrote: Sry: if((x1 < 0) & (x2 >= 0)){ This looks like a bug, with & instead of &&. -- Simon
Re: Variable below zero but if statement doesn't grab?
On Sunday, 27 December 2015 at 16:52:39 UTC, TheDGuy wrote: I don't understand why my program goes into the if statement if the debugger shows, that the variable "discriminant" is below zero even though: "if(discriminant > 0)"? I have a hard time believing this. Does the problem persist if you swap out the entire control flow, beginning with that line, with the following? if (discriminant > 0) writeln("bigger than zero"); else writeln("not entering the 'if'");
Re: segfault in invariant { assert(super); }
On Monday, 21 December 2015 at 20:29:14 UTC, Steven Schveighoffer wrote: 1) Is this recursion expected? Yes. assert calls the virtual invariant function, which in the case of super is equivalent to this. So you are essentially calling assert(this). 2) The example is a dustmite'd version of this: It seems like something you shouldn't do. AFAIK, invariant should not call any public functions on your existing class. Thanks for the reply! Yeah, this helps for a clearer picture of what's happening. In particular, even though all invariants of a class hierarchy are tested instead of only the most-subclassed-one, triggering the invariant check remains virtual. I didn't know that. Even if Base.f() is const, it's not allowed inside Derived.invariant(). This is again understandable: By OOP principles, Derived shouldn't impose further restrictions on Base than what Base imposes on itself already. (good idea to file an enhancement report). For that, I was trying earlier today to find the exact instances of when there is a warning, and when there is not. I didn't get warnings to come up consistently. (Even the case I described in question 2 doens't always give a warning.) I'd have to take a look at this some time again. -- Simon
segfault in invariant { assert(super); }
Hi, the following code compiles fine, then segfaults upon running. class Base { this(int) { } } class Derived : Base { this(int a) { super(a); } invariant() { assert (super); } } void main() { new Derived(5); } Tested both with dmd 2.069.2 on Linux 64-bit, and on dpaste's dmd 2.069.1: http://dpaste.dzfl.pl/4b9475c668f1 Backtrace on my home machine: Program received signal SIGSEGV, Segmentation fault. 0x004246a5 in _D9invariant12_d_invariantFC6ObjectZv () (gdb) bt #0 0x004246a5 in _D9invariant12_d_invariantFC6ObjectZv () #1 0x00647bf0 in _D3app7Derived6__initZ () #2 0x7f7ff030 in ?? () #3 0x0042301f in _D3app7Derived12__invariant1MxFZv (this=0x0) at source/app.d:7 Backtrace stopped: previous frame inner to this frame (corrupt stack?) So, looks like endless recursion inside the invairant. Questions: 1) Is this recursion expected? 2) The example is a dustmite'd version of this: I have a public final method Base.f(), and the compiler won't let me call f() in Derived's invariant. This is understandable, because f() is also a public method of Derived. However, I can call super.f() explicitly in Derived's invariant, with no compiler error. Is that expected to work, or should it lead to a similar segfault? (I get the segfault.) -- Simon
alias butAtLeast = max; 5.butAtLeast(6);
DMD v2.069.2-b1 on Linux. import std.algorithm; int a = max(5, 6);// works, a == 6 int b = max!(int, int)(5, 6); // works, manual instantiation int c = 5.max(6); // works, UFCS call I would like to use the last syntax, but with an alias. alias butAtLeast = max; // works int d = butAtLeast(5, 6); // works int e = 5.butAtLeast(6); // error: no property 'butAtLeast' for type 'int' Aliasing the instantiated function 'max!(int, int)' instead of aliasing 'max' doesn't help: The 'int e' line will fail with the exact same error. Can I get the alias to work somehow in an UFCS chain? -- Simon
Re: alias butAtLeast = max; 5.butAtLeast(6);
By putting it in the top level. I believe this is intentional but I don't remember the reasoning. On Saturday, 12 December 2015 at 13:34:09 UTC, ZombineDev wrote: This is due to limitation of function-local aliases. If you put the alias outside it will work: http://dpaste.dzfl.pl/4fb06cbbfad2. Thanks for both of these quick replies -- doing it similar to that example, it works for me too now. Good to know this little workaround. I'd love to see the design reason for the limitation. Right now, the error message (property doesn't exist at all) seems to be misleading. But getting all corner cases right is always tricky. :-) Perhaps a simpler way achieve this is to use renamed imports: The Identity template can also helpful in some situations: Thanks, will read for inspiration! -- Simon
Range violation instead of empty slice on a[3 .. 2]
string a = "hello"; string b = a[3 .. 2]; I expect b to become an empty slice, because 3 is >= 2 already after 0 increments, making the slice length 0. Instead, the code throws a range violation. Expressions of this kind come up, e.g., when taking slices near the end of arrays, like "slice = a[b.length .. $];". To make this robust, I need an extra check for b.length > a.length, returning null in this case, otherwise a[b.length .. $]. What's the design reason to prefer throwing over returning an empty slice? -- Simon
Re: Range violation instead of empty slice on a[3 .. 2]
On Saturday, 21 November 2015 at 18:28:51 UTC, BBaz wrote: this is only an error if bounds checking is not turned on. If you compile your example with DMD option "-boundscheck=off", nothing happens, and the slice will be equal (here) to a[3..$]; Thanks for the hint, I tested this with -boundscheck=off. Then, a[3..2] generates a slice length of (size_t.max), again different from what I might want. If the reason for this behavior (huge slice length instead of null slice) is performance during disabled bounds checking, then I'm fine with having to make the extra check. -- Simon
Re: Range violation instead of empty slice on a[3 .. 2]
On Sunday, 22 November 2015 at 00:24:43 UTC, Jonathan M Davis wrote: this is only an error if bounds checking is not turned on. It's a logic error regardless. you're going to have to create a wrapper. Right, I am using a wrapper, and I'm not relying on any behavior of a[3..2] during -boundscheck=off. How does the runtime know that you're not just providing it garbage values? The runtime flags an empty slice as an error here, seemingly without reason, because the slice can't access any element outside of bounds. However, considering (2U - 3U) > 0, I understand that there is no way to catch this problem without comparing the two bounds. And the comparison is designed to be skippable for speed. Therefore, 3..2 is reasonably flagged as an error. So, thanks for pointing it it out again! -- Simon
Mixin template, "no identifier for declarator"
Hi, I'd like to generate several very similar class methods with a mixin template. The mixin template shall take alias parameters, so that different methods can bind it to different fields. Reduced problem case: class A { int myField; mixin template fieldSetter(alias whatField) { whatField = newVal; } int setMyField(in int newVal) { mixin fieldSetter!myField; } } Compiler error message, DMD64 v2.068.2, line 6 is "whatField = newVal;": (6): Error: no identifier for declarator whatField (6): Error: declaration expected, not '=' I believe I'm following as closely as appropriate what's described at http://dlang.org/template-mixin.html under "Mixins can parameterize symbols using alias parameters". Why does it error out on whatField, apparently deeming it to be a type? Can I get this done with mixin templates? (I'd like to avoid string mixins, the workaround with them got a little ugly.) -- Simon
Re: Mixin template, "no identifier for declarator"
On Tuesday, 27 October 2015 at 08:41:24 UTC, Andrea Fontana wrote: Template mixins can be used only for declaration. Thanks for the quick reply! I didn't know that. Now the error message makes sense. Probably what you need is a (non-template) mixin. Yes, it's gonna be a string mixin, or a private method with lots of ref parameters. -- Simon
Re: Enumap -- a lightweight AA alternative when your keys are enums
On Sunday, 13 September 2015 at 03:33:15 UTC, rcorre wrote: I've released v0.4.0, which implements foreach with ref, and (hopefully) atones for my crimes against const-correctness. You should be able to modify values in a loop and work with const/immutable Enumaps. Thanks for the feedback! Yes, the 0.4.x version works with my examples perfectly. Thanks for adding const support! (I haven't tested yet every combination of const/mutable Enumap, const/mutable foraech-value, and direct/ref foreach-value. My examples are exactly what I'd do in normal projects anyway, mapping enum-values to ints.) -- Simon
Re: Enumap -- a lightweight AA alternative when your keys are enums
On Friday, 11 September 2015 at 04:02:17 UTC, rcorre wrote: On Friday, 11 September 2015 at 03:25:58 UTC, SimonN wrote: Hi, I've ran into a compilation error when iterating over a const Enumap. In the following code: Interesting, thanks for pointing that out. I don't think I did a great job with const-correctness here, I'll take a look tomorrow. It should definitely be possible to iterate over (and index, etc...) a const/immutable Enumset, though you're right that it doesn't work right now. No worries, take your time! Thanks for the quick clarification. I've also tested a couple ways of assigning in a foreach. Continuing from my code above (struct A { Enumap!(MyEnum, int) map; /* ... */ }), I've tried this in the main function: int some_value = 100; A a; foreach (MyEnum e, ref val; a.map) val = ++some_value; a.mutable_output(); foreach (MyEnum e, ref val; a.map) a.map[e] = ++some_value; a.mutable_output(); Output: e1: 0 e2: 0 e3: 0 e1: 104 e2: 105 e3: 106 Since I have been using "ref val" in the first loop, I expected the output to be instead: e1: 101 e2: 102 e3: 103 e1: 104 e2: 105 e3: 106 -- Simon
Re: Enumap -- a lightweight AA alternative when your keys are enums
On Friday, 11 September 2015 at 02:17:25 UTC, rcorre wrote: I frequently find myself needing a data structure that maps each member of an enum to a value; something similar what Java calls an EnumMap (http://docs.oracle.com/javase/7/docs/api/java/util/EnumMap.html). I couldn't find any D implementation out there, so I wrote a little module for it. Enumap is available on Github (https://github.com/rcorre/enumap) and via dub (http://code.dlang.org/packages/enumap). Docs are hosted at http://rcorre.github.io/enumap/. Hi, this looks excellent! I've been playing around with it, and am looking forward to using it regularly. I've ran into a compilation error when iterating over a const Enumap. In the following code: import std.stdio; import std.conv; import enumap; enum MyEnum { e1, e2, e3 } struct A { Enumap!(MyEnum, int) map; void mutable_output() { foreach (MyEnum e, int i; map) writefln("%s: %d", e.to!string, i); } void const_output() const { foreach (MyEnum e, const int i; map) writefln("%s: %d", e.to!string, i); } } ...the first method (mutable_output) compiles and works with no errors. The const method, however, gives: source/app.d(19,13): Error: invalid foreach aggregate this.map, define opApply(), range primitives, or use .tupleof". It doesn't seem to matter whether I put const int, or int, in the foreach statement. What's the idiomatic way to loop over a const Enumap? :-) -- Simon
Re: Arrays of structs
Hi, On Thursday, 27 August 2015 at 10:05:31 UTC, John Burton wrote: understanding is that structs have deterministic destructors - they are called when the struct goes out of scope Yes, when they are declared right at the scope, and not contained in something that might live past the current scope. However if I add them to a dynamic array... Then the destructor appears to be called at some random time later. So it looks like it's the garbage collection that is doing this. Yeah. That seems to go against the specification of how struct works... I'm not creating the item with new and as far as I can tell the array is storing instances of objects, not pointers to objects? The array is storing the full structs, yes. The array is GC-ably allocated and will therefore not go out of scope at end of scope. Because the array doesn't vanish here, the structs inside will not go out of scope either; they treat the array as their scope. (I'm sure others could explain this more formally.) There is no reference left to the array, so the GC may at a random later time deallocate the array, and thereby call ~this() on each struct. Is my understanding correct? Explicit new is not the only way to put objects on the GC'ed heap. Putting them in a GC-ed array like this is another way. Or having them as a component in a class, then instantiating that class. Is it documented anywhere how memory allocation works for this? I'll leave this for others, too. Is a dynamic array in fact storing an array of GC'd pointers to the structs? No, it's the full struct. -- Simon
Re: Empty struct, any runtime cost?
On Wednesday, 19 August 2015 at 09:54:33 UTC, SimonN wrote: Hi, I've found this thread (Theoretical best practises): http://forum.dlang.org/thread/codmadrwuyqxbklmu...@forum.dlang.org My goal is the same; I'm only more wary of putting debug/version everywhere. If the empty struct isn't optimized away fully, I'd still be up for what's recommended in that thread. -- Simon
Empty struct, any runtime cost?
Hi, in a release-like build, I'm using the tharsis profiler, which is a frame-based profiler. Zone is a RAII struct that measures how long its own lifetime is. with (Zone(my_profiler, zone name to appear in output)) { do_expensive_work(); do_some_more_work(); } // Zone goes out of scope here I would like to use this code without modification in a release build without profiling. I would rather not put version statements everywhere. I have only one version statement in a single file that's included by all files doing profiling: version (release_with_profiling) { public import tharsis.prof; } else { class Profiler { } struct Zone { this(Profiler, string) { } } } Using that, the first code sample compiles in the non-profiling build, where Zone is an empty struct. * Will the empty struct get optimized away completely by the compiler, at least if we pass -O -inline? I'd really like that, I have profiling code in several inner loops. * If not, what other approach could be usable to keep boilerplate in most source files to a minimum? -- Simon
Re: Template mixin can not introduce overloads
On Thursday, 25 June 2015 at 03:49:04 UTC, Tofu Ninja wrote: Is this intended or is it a bug? On Thursday, 25 June 2015 at 03:53:58 UTC, Adam D. Ruppe wrote: Intended, the mixin template works on the basis of names. This The extra step is easy though: alias the name in: I would like to to this with constructors instead of normal methods. I have tried to mix in a constructor as follows: #!/usr/bin/rdmd import std.stdio; mixin template MyConstructor() { this(int x, float y) { writefln(%d, %f, x, y); } } class Base { mixin MyConstructor my_ctor; this(string s) { writefln(s); } alias my_ctor this; } void main() { Base b = new Base(3, 4.5); } $ ./mixinctor.d ./mixinctor.d(17): Error: constructor mixinctor.Base.this (string s) is not callable using argument types (int, double) Failed: [dmd, -v, -o-, ./mixinctor.d, -I.] Doing it with alias this = my_ctor; errors out too, and demands me to use alias my_ctor this; as in the original code. Can I get this to work at all? Or does alias this (for multiple subtyping) fundamentally clash here with alias my_ctor this? -- Simon
Re: How to realize copyable/postblit class
On Saturday, 13 June 2015 at 08:52:59 UTC, John Colvin wrote: perhaps: class A { struct S { // ... } S s; alias s this; this(A rhs) { s = rhs.s; } } I'm using this now, and it doesn't feel like a workaround too much. For something with 5 value fields, it's already shorter than the original solution. Thanks! :-) -- Simon
How to realize copyable/postblit class
Hi, I have a few classes with need for deeper copying. I don't want a bitwise copy necessarily. Ideally, I'd implement this(this). I've thought about changing them to struct. However, the type feels much more like a D class than a D struct. It's often passed by reference, and it's not plain old data. Changing it to struct for the sole benefit of this(this) seems to be a bad tradeoff. (Use case: Backing up game states in a for savestating/networking.) I've resorted to a C++-style copy constructor: this(T rhs) { myvalue = rhs.myvalue; myarray = rhs.myarray.dup; // ... } Downside: Boilerplate, each member appears once in the declarations, a second time in the copy constructor. Alternative approaches seem to implement T T.dup() or T T.clone(). Apparently, one has to pick one of these equally good approaches, and stick with it throughout a codebase. It seems good to implement it only for the classes that need it, to minimize boilerplate. Is that the state of the art? -- Simon