Re: Syntax for Static Import of User Define Attributes
On Friday, 28 July 2023 at 11:54:12 UTC, Steven Schveighoffer wrote: On 7/28/23 4:15 AM, Vijay Nayar wrote: I tried it and it worked for me. The template-argument syntax is normal. It's just a list of types or expressions (i.e. not a function argument list) What is the error? -Steve You're right, I must have tried something slightly different without realizing it. The syntax that works seems to be to enclose the entire fully-qualified-name of the user-defined-attribute along with all its arguments within parentheses. However, this makes me wonder. Is there any reason why the `@` shouldn't recognize the dots in a fully-qualified-name on its own, without the need for parentheses?
Re: Syntax for Static Import of User Define Attributes
On Thursday, 27 July 2023 at 21:24:44 UTC, Dennis wrote: On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` Try: ```D @(vibe.data.serialization.name("name")) ``` This one causes a different error, because it invokes the template-argument syntax: https://dlang.org/spec/attribute.html#uda
Re: class variable initialization
On Saturday, 15 April 2023 at 14:05:17 UTC, NonNull wrote: I want a way to default initialize a class variable to a default object (e.g. by wrapping it in a struct, because initialization to null cannot be changed directly). Such a default object is of course not available at compile time which seems to make this impossible. Can this be done in some way? Assuming you want a default object that is unique per class instance rather than shared among all instances of the same class, then I think the constructor might be where you want to initialize such a member. E.g. ``` class Var { int val; this(int val) { this.val = val; } } class MyClass { Var var; this() { var = new Var(3); } } ``` I believe if you do initialization at the class declaration level, then every instance of the class shares the same instance, e.g.: ``` class Var {} class MyClass { Var var = new Var(); } void main() { MyClass c1 = new MyClass(); MyClass c2 = new MyClass(); assert(c1.var is c2.var); } ```
Re: Error "Outer Function Context is Needed" when class declared in unittest
On Thursday, 5 January 2023 at 16:41:32 UTC, Adam D Ruppe wrote: On Thursday, 5 January 2023 at 16:38:49 UTC, Vijay Nayar wrote: Does that class inherit the scope of the function it is inside, similar to how an inner class does with an outer class? yup. They can see the local variables from the function. Glad to learn that. Having worked many years in the Java world, where basically "class" and "scope" are nearly synonymous, I just assumed that classes could only get the scope of other classes, it never occurred to me that it could get a scope from a function. Thanks for the explanation!
Re: Error "Outer Function Context is Needed" when class declared in unittest
On Thursday, 5 January 2023 at 13:47:24 UTC, Adam D Ruppe wrote: On Thursday, 5 January 2023 at 13:27:23 UTC, Vijay Nayar wrote: Why is this error only found when declaring a class in the unittest? A unittest is just a special function, it can run code and have local variables. classes and structs declared inside it have access to those local contexts, which it calls the outer function context. Make the outer class `static` too to lift it out of this and your error should go away. That's very informative, I didn't realize that `unittest` is actually a function. It raises another question one step deeper, what does it mean to define a non-static class within a function? Does that class inherit the scope of the function it is inside, similar to how an inner class does with an outer class?
Error "Outer Function Context is Needed" when class declared in unittest
I've run into an unexpected problem that only seems to happen in unittests, but not outside of them. Consider the following example: ``` unittest { class Ab { int a; string b; static class Builder { int _a; string _b; Builder a(int a) { _a = a; return this; } Builder b(string b) { _b = b; return this; } Ab build() { Ab t = new Ab(); t.a = _a; t.b = _b; return t; } } } Ab ab = new Ab.Builder() .a(1) .b("ham") .build(); assert(ab.a == 1); assert(ab.b == "ham"); } ``` This fails to compile with the following error: ``` Generating test runner configuration 'builder-test-library' for 'library' (library). Starting Performing "unittest" build using /usr/bin/dmd for x86_64. Building builder ~master: building configuration [builder-test-library] source/builder.d(58,16): Error: outer function context of `builder.__unittest_L41_C1` is needed to `new` nested class `builder.__unittest_L41_C1.Ab` Error /usr/bin/dmd failed with exit code 1. ``` However, if I move the class definition outside of the unittest block, then everything works fine: ``` class Ab { int a; string b; static class Builder { int _a; string _b; Builder a(int a) { _a = a; return this; } Builder b(string b) { _b = b; return this; } Ab build() { Ab t = new Ab(); t.a = _a; t.b = _b; return t; } } } unittest { Ab ab = new Ab.Builder() .a(1) .b("ham") .build(); assert(ab.a == 1); assert(ab.b == "ham"); } ``` ``` Generating test runner configuration 'builder-test-library' for 'library' (library). Starting Performing "unittest" build using /usr/bin/dmd for x86_64. Building builder ~master: building configuration [builder-test-library] Linking builder-test-library Running builder-test-library 2 modules passed unittests ``` Why is this error only found when declaring a class in the unittest?
Re: Best practice for dub registry package and module names
On Sunday, 4 September 2022 at 01:52:11 UTC, Ali Çehreli wrote: Let's say I have three modules that work together, which I want to register on dub: A, B, and C. Here I would take inspiration from the Java world, where a "domain" is used per project. Typically this domain is written from the most general part of the domain to the most specific, so "web.example.com" becomes "com.example.web". For example: ``` import org.springframework.boot.SpringApplication; ``` So you could have: com.alicorp.a, com.alicorp.b, and com.alicorp.c That being said, D is not Java, thus things like the company top-level domain could be left out and you end up with alicorp.a, alicorp.b, etc. Thus the problem of name collision goes away until someone else tries to take the name "alicorp". I believe this is why Java uses the full domain, because unique domain ownership is already a solved problem, they just ride along. Packages like `vibe` follow a similar mechanism, where all the useful modules and packages are nested under a single package.
Re: vibe.d requestHTTP in static this causes infinite loop?
On Friday, 20 May 2022 at 01:41:59 UTC, Ali Çehreli wrote: On 5/19/22 16:44, Vijay Nayar wrote: > If I remove the call from `static this()`, then the web call works as > normal. Any idea why calling vibe.d's `requestHTTP` function inside of a > module's static construction would cause an infinite loop? I am not experienced with vibe.d. 'static this' is executed per thread. If requestHTTP starts a new thread, then I can see how you would be in an infinite loop. I wonder whether it should be 'shared static this' (which is executed once per program, not per thread). Ali Very clever, you were exactly right. I had not thought of that, but that is indeed what was happening.
vibe.d requestHTTP in static this causes infinite loop?
I've encountered an unusual behavior that I have no good explanation for. Consider the following code example: ```d import vibe.core.log : logInfo; import vibe.http.client : requestHTTP, HTTPClientRequest, HTTPClientResponse; import vibe.http.common : HTTPMethod; import vibe.stream.operations : readAllUTF8; void doThing() { requestHTTP("http://example.com/";, (scope HTTPClientRequest req) { logInfo("Setting request method."); req.method = HTTPMethod.GET; }, (scope HTTPClientResponse res) { logInfo("Log point 1"); string data = res.bodyReader.readAllUTF8(); logInfo("Log point 2: %s", data); }); } static this() { logInfo("--- static this() ---"); doThing(); } void main(string[] args) { logInfo("--- main() ---"); doThing(); } ``` The output of this program is actually an infinite loop with output of the form: ``` [Eventcore DNS Lookup() INF] --- static this() --- [Eventcore DNS Lookup() INF] --- static this() --- ``` If I remove the call from `static this()`, then the web call works as normal. Any idea why calling vibe.d's `requestHTTP` function inside of a module's static construction would cause an infinite loop?
Re: Can std.variant be used with std.container.rbtree?
On Saturday, 2 April 2022 at 14:35:10 UTC, Vijay Nayar wrote: The `tryMatch` method fails to compile, and instead I get the following error: ```d /dlang/dmd/linux/bin64/../../src/phobos/std/sumtype.d(2004): Error: static assert: "`handlers[0]` of type `int function(ref ubyte[] _1, ref ubyte[] _2) pure nothrow @nogc @safe` never matches" ``` Through sheer trial and error, I discovered that changing the handler arguments from `ref ubyte[]` to `const ref ubyte[]` the error goes away. However, I did not find any information in the documentation or code that made this requirement clear. It was basically a guess based on the fact that `string` has no trouble but `ubyte[]` did, and string is basically just `immutable(char[])`. So far, I'm finding that learning to use `SumType` is significantly more cryptic than `Variant`, by a large margin. I'll still give it a shot of course, because I want to get past this problem.
Re: Can std.variant be used with std.container.rbtree?
On Saturday, 2 April 2022 at 10:04:49 UTC, vit wrote: Try use ```std.sumtype```. I'm playing with SumType to see how it works, and I must be doing something silly, because it fails to compile with the first example type I attempted. Consider the following: ```d import std.sumtype; import std.algorithm : cmp; alias VarType = SumType!(double, ubyte[]); int opCmp(const ref VarType v1, const ref VarType v2) { alias doMatch = tryMatch!( (ref ubyte[] _1, ref ubyte[] _2) => cmp(_1, _2), (_1, _2) => _1 < _2 ? -1 : (_2 < _1 ? 1 : 0)); return doMatch(v1, v2); } void main() { VarType b1 = cast(ubyte[]) [0x01, 0x02, 0x03]; VarType b2 = cast(ubyte[]) [0x01, 0x02, 0x04]; b1 > b2; } ``` The `tryMatch` method fails to compile, and instead I get the following error: ```d /dlang/dmd/linux/bin64/../../src/phobos/std/sumtype.d(2004): Error: static assert: "`handlers[0]` of type `int function(ref ubyte[] _1, ref ubyte[] _2) pure nothrow @nogc @safe` never matches" /dlang/dmd/linux/bin64/../../src/phobos/std/sumtype.d(1739): instantiated from here: `matchImpl!(const(SumType!(double, ubyte[])), const(SumType!(double, ubyte[])))` onlineapp.d(10):instantiated from here: `tryMatch!(const(SumType!(double, ubyte[])), const(SumType!(double, ubyte[])))` ``` I'm not super sure why this handler would not match. If I do simple types like `double` or `int` it works, it even works with `string`, but the moment I include `ubyte[]`, it no longer compiles. In this example, I eliminated all other array types aside from `ubyte[]`, so there should be no conflicts in theory.
Re: Can std.variant be used with std.container.rbtree?
On Saturday, 2 April 2022 at 14:23:31 UTC, Salih Dincer wrote: If your type includes opCmp() there is no reason not to use rbTree. I am using rbTree, the problem is when I try to use it with Variant, at which point it blows up.
Re: Can std.variant be used with std.container.rbtree?
On Saturday, 2 April 2022 at 10:03:19 UTC, JG wrote: You need an order on the elements in a red black tree. Am I correct in thinking you want a container of the form given a key (a string) recover some data (of different types). If so make the elements you store in the red black tree tuples (k,d) where k is a string and d is a variant. Define the order (k1,d1)<(k2,d2) if k1when you search for a key you get the pair and take the second part. I hope this makes sense. This is correct, although it seems that Variant is not suitable for this purpose. The data structure roughly looks like this: - FieldName (string) => Index - Index has PrimaryKey (Variant) and a Value (also Variant) - Index Entries are a tuple of the form (PrimaryKey, Value) Each index is roughly used by passing in a value, and it spits out a range of PrimaryKeys that are equal, lessThan, or greaterThan that value depending on what's needed. The special Entry data type (rather than just the raw value) was added because I still need the IDs when I look up values, and I think using the Entry is every so slightly more efficient than maintaining a separate data structure keeping a set of Ids per Value. Variant itself works well for comparison, because it simply passes down the compare operation to the underlying type, but it's major flaw seems to be the lack of support for noThrow, @safe, etc. On Saturday, 2 April 2022 at 10:04:49 UTC, vit wrote: Try use ```std.sumtype```. Very good suggestion, I haven't tried this before. I'll do some digging to see if I can make it work. Because it requires one to list the data types in advance, it can work for primary keys, however, it may not work in my particular use case because the values too that I'm organizing are also Variants. I hope it works.
Can std.variant be used with std.container.rbtree?
Consider the following program: ```d void main() { import std.stdio; import std.container.rbtree; import std.variant; // alias Type = int; // Works with no problem. alias Type = Variant; // Produces error. auto rbTree = new RedBlackTree!(Type); rbTree.stableInsert(Type(3)); rbTree.stableInsert(Type(2)); rbTree.stableInsert(Type(4)); foreach (v; rbTree.upperBound(Type(2))) { writeln(v); } } ``` A `RedBlackTree` constructs and runs perfectly fine using "int" as the data type, but it seems to blow up as soon as I use `std.variant : Variant`. ``` Compilation output (1: ) /dlang/dmd/linux/bin64/../../src/phobos/std/container/rbtree.d(1116): Error: `@safe` function `std.container.rbtree.RedBlackTree!(VariantN!32LU, "a < b", false).RedBlackTree.toHash` cannot call `@system` function `std.container.rbtree.RBRange!(RBNode!(VariantN!32LU)*).RBRange.front` /dlang/dmd/linux/bin64/../../src/phobos/std/container/rbtree.d(682): `std.container.rbtree.RBRange!(RBNode!(VariantN!32LU)*).RBRange.front` is declared here /dlang/dmd/linux/bin64/../../src/phobos/std/container/rbtree.d(1116): Error: destructor `std.variant.VariantN!32LU.VariantN.~this` is not `nothrow` /dlang/dmd/linux/bin64/../../src/phobos/std/container/rbtree.d(1113): Error: function `std.container.rbtree.RedBlackTree!(VariantN!32LU, "a < b", false).RedBlackTree.toHash` may throw but is marked as `nothrow` onlineapp.d(10): Error: template instance `std.container.rbtree.RedBlackTree!(VariantN!32LU, "a < b", false)` error instantiating ``` This may seem like a strange thing to do, but it is useful when trying to have set of indexes, each of which is used on a different data field. The set of indexes can share a common data-type using Variant, which allows one to do things like have associative arrays of indexes which you can look up by field name. However, it looks like `Variant` doesn't have the various attributes desired by `RedBlackTree`. Is there a way to make them compatible? Do I need to avoid std.container.rbtree and make my own which doesn't require these attributes, or do I need to implement my own version of Variant using a union and try to make it safe/nothrow/etc.?
Re: How to create delegates with an independent scope?
On Wednesday, 30 March 2022 at 12:53:10 UTC, vit wrote: use two delegates :) ```d (){ // Deliberately create a copy to keep in delegate scope. string myStr = i.dup; // The delegate will hopefully carry this copy around in its own scope. funcs ~= (() => myStr ~ " sandwich"); }(); ``` Very interesting. Both this and creating a "function creator function" work, and it seems clear that functions create their own scopes. However, it seems that loops do not, is that correct? Maybe I was thrown off by the surrounding `{ }`, but I had assumed that loops created their own scopes.
How to create delegates with an independent scope?
Consider the following code example: ```d import std.stdio; void main() { alias DelegateT = string delegate(); // An array of delegates, each has their own scope. DelegateT[] funcs; foreach (i; ["ham", "cheese"]) { // Deliberately create a copy to keep in delegate scope. string myStr = i.dup; // The delegate will hopefully carry this copy around in its own scope. funcs ~= (() => myStr ~ " sandwich"); } foreach (f; funcs) { writeln(f()); } } ``` The expected output is: "ham sandwich" and then "cheese sandwich". The actual output is: "cheese sandwich" and then "cheese sandwich". It seems that the variable `myStr` is in a sort of shared scope for both functions in the array, and the last value written to it dominates. How do I create a delegate that acts like a [closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures), that is, it carries with it the environment in which it was created?
Re: Cannot Call Super-Class Overloaded Function If Class has Function Override?
On Tuesday, 1 March 2022 at 09:06:59 UTC, vit wrote: On Tuesday, 1 March 2022 at 08:40:12 UTC, Vijay Nayar wrote: I've randomly encountered a strange error, and I cannot find any explanation for it in the official documentation of syntax. [...] Here is more info (3.): https://docarchives.dlang.io/v2.078.0/spec/function.html#function-inheritance Very well spotted, thank you for that! I'm a bit surprised at this behavior though. Do you happen to know why it is considered bad to take into account the overloads of a super-class when resolving a call in a derived-class?
Cannot Call Super-Class Overloaded Function If Class has Function Override?
I've randomly encountered a strange error, and I cannot find any explanation for it in the official documentation of syntax. Essentially, a class cannot call function overload in a super-class if the class itself contains an override. Is this a bug? Is this on purpose? Take a look at `B.otherThing()` below. ``` d void main() { abstract class A { // An abstract method for sub-classes abstract void doThing(string a, size_t b); // A convenience helper. void doThing(string a) { doThing(a, a.length); } } class B : A { // If this overload exists, something strange happens... override void doThing(string a, size_t b) { } void otherThing() { // Error: `B.doThing(string a, ulong b)` // is not callable using argument // types `(string)` doThing("hello"); super.doThing("hello"); // OK } } } ```
Re: Detecting ElementType of OutputRange
On Saturday, 26 February 2022 at 12:39:51 UTC, Stanislav Blinov wrote: Considering that `put` is quite typically implemented as a template, I don't think that would be possible in general. That is what I found as well, for example, the implementation of `put` from `Appender` and `RefAppender`, thus the algorithm fails to detect the `put` methods. The question is, do you really need that? Your `BufferedOutputRange` can test the underlying range using `isOutputRange` in its own implementation of `put`, where the type of element is known, i.e. to test whether it can bulk-write a slice (or a range of) elements or has to make per-element calls to `put`. This is exactly what I was doing, having the user pass in the element type themselves, and then the BufferedOutputRange check for both `isOutputRange!(ORangeT, ElemT)` and `is(typeof(ORangeT.init.put([ ElemT.init ])))`. In short, `isOutputRange` has many ways to be satisfied, (https://dlang.org/phobos/std_range_primitives.html#.put), but I want to restrict things further to only output streams that can do a bulk put. Thanks for you advice. While automatic detection would be a nice convenience, it's not a deal breaker and it's also not unreasonable to expect the caller to know the element type they are inserting either.
Re: Detecting ElementType of OutputRange
On Saturday, 26 February 2022 at 11:44:35 UTC, Stanislav Blinov wrote: https://dlang.org/phobos/std_range_primitives.html#isOutputRange This method requires the caller to explicitly declare the output range element type, which I was hoping to have to avoid, if it can be detected using reasonable assumptions.
Detecting ElementType of OutputRange
I was working on a project where it dealt with output ranges, but these ranges would ultimately sink into a source that would be inefficient if every single `.put(T)` call was made one at a time. Naturally, I could make a custom OutputRange for just this resource, but I also got the idea that I could make a generalized `BufferedOutputRange` that would save individual `.put(T)` calls into memory until a threshold is reached, and then make one bulk call to the output stream it wraps with a single `.put(T[])` call. While working on the template for this buffering OutputRange, I originally used `ElementType` on the output range I was given, hoping to detect what type of `.put(T)` is permitted. However, I found out that `ElementType` only works for input ranges as you can see here: https://github.com/dlang/phobos/blob/6bf43144dbe956cfc16c00f0bff7a264fa62408e/std/range/primitives.d#L1265 Trying to find a workaround, I ultimately created this, and my question is, is using such a template a good idea or a terrible idea? Is it safe to assume that ranges should have a put method that may take arrays that I can detect? Should I give up on the idea of detecting the OutputRange type, and instead require the programmer to explicitly declare the output type for fear of them using a range that doesn't take arrays? Here is the source of what I was thinking of, let me know your thoughts: ``` d import std.range; import std.traits; // A specialization of std.range.ElementType which also considers output ranges. template ElementType(R) if (is(typeof(R.put) == function)) // Avoid conflicts with std.range.ElementType. { // Static foreach generates code, it is not a true loop. static foreach (t; __traits(getOverloads, R, "put")) { pragma(msg, "Found put method, params=", Parameters!(t).length); // Because all code gets generated, we use a 'done' alias to // tell us when to stop. static if (!is(done)) { // Attempts to save Parameters!(t) into a variable fail, so it is repeated. static if (Parameters!(t).length == 1 && is(Parameters!(t)[0] T : T[])) { pragma(msg, "put for array found"); // Setting the name of the template replaces calls // to ElementType!(...) with T. alias ElementType = T; alias done = bool; } else static if (Parameters!(t).length == 1 && is(Parameters!(t)[0] T)) { pragma(msg, "put for single found"); alias ElementType = T; alias done = bool; } } } static if (!is(done)) { alias ElementType = void; } } unittest { // Works for simple 1-element puts for structs. struct Ham0(T) { void put(T d) {} } assert(is(ElementType!(Ham0!float) == float)); // Works for classes too, which have array-based puts. class Ham1(T) { void put(T[] d) {} } assert(is(ElementType!(Ham1!float) == float)); // Distracting functions are ignored, and if single & array // puts are supported, the element type is still correct. struct Ham2(T) { void put() {} void put(float f, T[] d) {} void put(T[] d) {} void put(T d) {} } assert(is(ElementType!(Ham2!int) == int)); } ```
Re: DDoc Reference Links point to /docs/docs instead of /docs?
On Monday, 21 February 2022 at 16:58:43 UTC, Adam D Ruppe wrote: On Monday, 21 February 2022 at 15:35:41 UTC, Vijay Nayar wrote: I'm a bit surprised I've never heard of `adrdox` before now. yeah i don't advertise much. it is what runs on my dpldocs.info website though which auto-generates docs for dub packages. Regarding ddoc, should I submit a bug report? If so, is ddoc considered part of the compiler? Yeah, it is part of dmd, so you can file on issues.dlang.org if you want. Bug reported here: https://issues.dlang.org/show_bug.cgi?id=22803
Re: DDoc Reference Links point to /docs/docs instead of /docs?
On Monday, 21 February 2022 at 13:18:01 UTC, Adam D Ruppe wrote: tbh ddoc is pretty bad, you should try my `dub run adrdox` instead which also creates html but its links actually work. I gave it a try and I must say that the documentation is formatted in a very good way, and as you said, all the links work. I'm a bit surprised I've never heard of `adrdox` before now. Thank you kindly for that! Regarding ddoc, should I submit a bug report? If so, is ddoc considered part of the compiler?
DDoc Reference Links point to /docs/docs instead of /docs?
Greetings everyone, I have a question regarding the use of [relative links](https://dlang.org/spec/ddoc.html#reference_links) in DDoc. According to the specification, you can include a reference to an object that is in scope using square brackets, e.g. `[Object]`. One of my current projects is to add support to [Avro](https://avro.apache.org/docs/current/index.html) in D, and I encountered something unusual. Consider the following code snippets. ```d // File: source/avro/parser.d module avro.parser; class Parser { /// Builds a [Schema] using a path to a ".avsc" file. public Schema parseFile(string fileName) { // ... } ``` ```d // File: source/avro/schema.d module avro.schema; class Schema { // ... } ``` When I build the documentation using `dub build -b docs`, which creates a bunch of individual `.html` files under the `docs` folder, but there is no `index.html` or anything else. I start by browsing to `file:///home/vnayar/projects/avro-d/docs/parser.html` The documentation for the `Parser::parseFile` creates a link like so: ```html Builds a class="code">Schema using a path to a ".avsc" file. ``` However, when I click the `Schema` link in my browser, the relative link of `docs/schema.html` actually is relative to the current file, thus, it takes me to `file:///home/vnayar/projects/avro-d/docs/docs/schema.html#Schema`. Because the folder `docs/docs` does not exist, I just get a file-not-found error. Am I using DDocs incorrectly?
Function Parameters without Names?
I encountered an odd bug in a project of mine which is illustrated in the example below: ```d class Thing { int val; this(int) { this.val = val; } } void main() { auto t = new Thing(3); assert(t.val != 3); } ``` The problem is that the parameter of the constructor actually has no name at all. Thus, the statement `this.val = val` simply sets the member variable to its own value, thus it stays the same as `int.init`. According to the [specification](https://dlang.org/spec/function.html), this is permissible via the following grammar rules: `FuncDeclaration` => `FuncDeclarator` => `FuncDeclaratorSuffix` => `Parameters` => `ParameterList` => `Parameter` => `Declarator` => `ParameterAttributes_opt Type`. What is the main motivator to allow parameters with no names? Do they get an automatic implied name like `_` or something?
Re: Approach to Integration Testing in D
On Sunday, 6 February 2022 at 17:36:05 UTC, Vijay Nayar wrote: On Friday, 4 February 2022 at 17:39:00 UTC, H. S. Teoh wrote: On Fri, Feb 04, 2022 at 12:38:08PM +, Vijay Nayar via When working on a dub configuration needed to separately run integration tests that operate on the fully built program from the outside, treating it like a black-box, I had run into a number of problems because `dub` implicitly created configurations called `application` or `library` only if you have no configurations of your own defined. But as soon as I added my own configuration, those default configurations were no longer being created and I suddenly found myself seeing strange errors when trying to run unit-tests or builds. See [GitHub Dub Issue #1270](https://github.com/dlang/dub/issues/1270). However, I did finally navigate the tricky waters and make a configuration that does actually work for `dub build`, `dub test` and `dub test --config=integration`. I thought I would share what I found here: ```sdl authors "Vijay Nayar" copyright "Copyright © 2019, Vijay Nayar" description "Receives data from sources, converts it to protobufs, and delivers it in batches to stem." license "proprietary" name "mouth" targetPath "target" # By default, 'dub' creates either an 'application' or 'library' config if no # configuration exists. # Because we need a configuration for integration tests, this forces us # to create the 'application' config as well. # # The 'dub test' command searches for the first 'library' target type, and # if none exists, the first 'executable'. # Used by 'dub build' and 'dub test'. configuration "application" { targetName "mouth" targetType "executable" dependency "funnel:common" path="../" dependency "funnel:proto" path="../" dependency "nanomsg-wrapper" version="~>0.5.3" dependency "poodinis" version="~>8.0.3" dependency "vibe-d" version="~>0.9.4" # This must be listed so that 'dub test' knows to ignore it. mainSourceFile "source/app.d" } # Used by 'dub test --config=integration' configuration "integration" { targetName "mouth_integration" # This must not be 'library', or it will be used by 'dub test'. targetType "executable" # The "source/" directory is automatically included, it must be explicitly # excluded instead. excludedSourceFiles "source/*" # The integration tests' source is in './integration'. sourcePaths "integration" importPaths "integration" # Make sure the executable we are testing exists. preBuildCommands "echo IMPORT_PATHS=$$IMPORT_PATHS" preRunCommands "cd $PACKAGE_DIR ; dub build" } ```
Re: Approach to Integration Testing in D
On Friday, 4 February 2022 at 17:39:00 UTC, H. S. Teoh wrote: On Fri, Feb 04, 2022 at 12:38:08PM +, Vijay Nayar via Digitalmars-d-learn wrote: [...] I am still in the process of experimenting, but the advice on this thread has all been very helpful. Right now I'm experimenting by creating a separate "integration" `dub` configuration which uses `std.process : spawnProcess` to run my vibe.d-based web server and try out requests on it. However, in any kind of large organization using a build server, even when there are multiple services/builds running in the same environment, it can be very inconvenient use a fixed port on which to run this server. Another running service, another person's build, or a test that ran and died without closing its sockets can lead to conflicts during development. In order to solve that problem of port conflicts during integration testing, I converted a utility class from the Java Spring Framework into D and wanted to share it here: https://gist.github.com/vnayar/04c6172d9f9991062974585bb3ccc8a4 The usage is very simple, and can be used by integration tests to pick random free ports on which to run their tests. Here is one of the available methods: ```d /** * Find an available TCP port randomly selected from the range * \[ [PORT_RANGE_MIN], [PORT_RANGE_MAX] \]. * Returns: an available TCP port number * Throws: Exception if no available port could be found */ ushort findAvailableTcpPort() { return findAvailableTcpPort(PORT_RANGE_MIN); } unittest { foreach (ushort i; 0..10) { ushort port = findAvailableTcpPort(); assert(port >= PORT_RANGE_MIN && port <= PORT_RANGE_MAX); } } ```
Approach to Integration Testing in D
Greetings everyone, ## Question What is your approach to integration testing in D? Do you use `unittest` blocks? Do you write stand-alone programs that interact with a running version of your program? Is there a library that makes certain kinds of testing easier? For example, if I have a D project based on vibe.d, and I have custom converters to receive REST API request bodies in different formats based on the "Content-Type" HTTP header and other converter for the response based on the "Accepts" header, what is the best approach to test the entire program end-to-end? ## Context Having done considerable work in Java using Spring and Spring Boot, it's very common to have [integration tests](https://softwaretestingfundamentals.com/integration-testing/), which the Spring Boot framework makes quite easy to set up with annotations like [@SpringBootTest](https://www.baeldung.com/spring-boot-testing#integration-testing-with-springboottest). In a nutshell, Spring Boot is built on top of dependency injection, with a "Context" acting as a container for all the objects (called Beans) that are created and injected into that container. `@SpringBootTest` lets the user pick and choose which objects will be created for the test, and then when the program is run, only those objects are loaded. This allows one to do things like, start a complete web server environment, test by sending a request to some endpoint, and then validate that the response is what you would expect. This is especially helpful to validate that you are using the Spring Framework correctly, e.g. that custom converters you created that allow messages to be received in binary [protobuf](https://developers.google.com/protocol-buffers/) format instead of JSON work correctly.
Re: How to make dub recursively build subPackages?
On Wednesday, 2 February 2022 at 19:03:35 UTC, Steven Schveighoffer wrote: On 2/2/22 1:42 PM, Vijay Nayar wrote: Dub is kind of a hot mess in terms of the dependency resolution and ways to specify projects. I would love to see it cleaned up/reimplemented. -Steve For your larger more complex projects, what build system do you use? So far I've been having good luck with dub, but I haven't done any mixed-language projects lately either.
Re: How to make dub recursively build subPackages?
On Wednesday, 2 February 2022 at 14:07:08 UTC, Steven Schveighoffer wrote: On 2/2/22 5:14 AM, Vijay Nayar wrote: If you have them in the same repository, my recommendation is to use path dependencies instead of versions. So, e.g.: ```sdl dependency "funnel:proto" path="./proto" // in main dub.sdl dependency "funnel:proto" path="../proto" // in sibling package ``` Because otherwise, dub is going to try and fetch the appropriate version from an online repository and not use your local files. Honestly, for packages in the same repository, I'm not sure why you would version them separately from the main package. I don't even know if that works. -Steve I made this change and it did indeed work correctly, thank you for that! Truthfully, it was not entirely clear to me how dub was deciding where to go to build. I had assumed that this was being done via the `subPackage` lines. The examples given in the offical documentation were also using versions, and I was following that: https://dub.pm/package-format-sdl.html#sub-packages
Re: How to make dub recursively build subPackages?
On Wednesday, 2 February 2022 at 10:14:25 UTC, Vijay Nayar wrote: Greetings folks, In my project, I have a parent package with several sub-packages, each of which builds into either a library or an executable. [...] I should point out there is 1 exception to subPackages not being recursive. The `dub clean` command does recurse, and there is source code for it here: https://github.com/dlang/dub/blob/3abaa4d5b7c3b2c21ab75370cd5330e9ae7bbd12/source/dub/dub.d#L880
How to make dub recursively build subPackages?
Greetings folks, In my project, I have a parent package with several sub-packages, each of which builds into either a library or an executable. I first started observing odd problems when I was running `dub build`, it would complain about different versions of vibe-d present, and it suggested running `dub upgrade`. After doing this, I noticed that most subPackages were not actually being upgraded. The only thing I have found thus far is to manually run each subPackage one at a time, e.g. `dub :proto; dub :common; ...`. Is it possible to get `dub upgrade` to recursively work on all sub-packages? My parent package dub.sdl file: ``` name "funnel" description "An in-memory queryable database for processing extreme loads of current data." authors "Vijay Nayar" copyright "Copyright © 2019, Vijay Nayar" license "proprietary" targetType "none" targetPath "target" dependency "funnel:proto" version=">=0.0.0" dependency "funnel:spout" version=">=0.0.0" dependency "funnel:stem" version=">=0.0.0" dependency "funnel:mouth" version=">=0.0.0" dependency "funnel:common" version=">=0.0.0" subPackage "./common" subPackage "./proto" subPackage "./mouth" subPackage "./stem" subPackage "./spout" ``` Each subPackage is structured in the same way, for example, the common subPackage: ``` authors "Vijay Nayar" copyright "Copyright © 2019, Vijay Nayar" description "Common logic between the mouth and spout components." license "proprietary" name "common" targetType "library" targetPath "target" dependency "funnel:proto" version="*" dependency "poodinis" version="~>8.0.3" dependency "vibe-d" version="~>0.9.4" ``` I mostly followed the dub documentation in setting up my project. https://dub.pm/package-format-sdl.html
Re: How to attach function attributes to delegate type?
On Wednesday, 27 February 2019 at 20:45:33 UTC, Alex wrote: On Wednesday, 27 February 2019 at 20:03:15 UTC, Q. Schroll wrote: For any type constructors like const, I can use ConstOf!T to get `T` with const attached. For a delegate/function type DG, e.g. int delegate(int), how can I get the @safe version of that type, i.e. int delegate(int) @safe? I tried alias SafeOf(DG) = DG @safe; but it didn't compile. The case is not @safe-specific; it's the same for all function attributes. At https://p0nce.github.io/d-idioms/ there is a demonstration for @nogc: ´´´ import std.traits; // Casts @nogc out of a function or delegate type. auto assumeNoGC(T) (T t) if (isFunctionPointer!T || isDelegate!T) { enum attrs = functionAttributes!T | FunctionAttribute.nogc; return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t; } ´´´ Didn't try this for other cases, however... When I need particular attributes, such as for a comparator, but also need to pass in a function as a template argument, one approach I've started to adopt is to only call this function from within a wrapper that has all the properties I want. For example: import std.stdio; class MyThing(T, alias LessF) { // This wrapper defines the conditions for a valid LessF. @safe @nogc private static bool less(in T t1, in T t2) { return LessF(t1, t2); } } void main() { MyThing!(int, (a, b) => a < b) a; // Compiles fine! MyThing!(int, (a, b) { writeln("Not @nogc!"); // Compiler error! return a < b; }) b; } The error looks like this, which is fairly readable too. onlineapp.d(6): Error: `@nogc` function `onlineapp.main.MyThing!(int, (a, b) { writeln("Not @nogc!"); return a < b; } ).MyThing.less` cannot call non-@nogc function
Re: What is the Utility of Parent Class Method Hiding in Inheritance?
On Wednesday, 16 January 2019 at 17:01:06 UTC, Steven Schveighoffer wrote: On 1/14/19 2:30 PM, Neia Neutuladh wrote: On Mon, 14 Jan 2019 09:10:39 +, Vijay Nayar wrote: a.foo(1); // issues runtime error (instead of calling A.foo(int)) Calling the function doesn't issue any sort of error. Overriding one overload without overloading or explicitly aliasing in the rest issues a compile-time error. If you got a runtime error instead, please create a bug report. I ran into this the other day, where I had a function of the same name in a child class, and found that all functions in the parent of the same name now became hidden, unless I add an alias statement. If the functions from the parent class are hidden but your code compiles, please create a bug report. Well, for sure, the documentation needs to be updated! It was 2.068 that removed the HiddenFuncError, and made this a compile error instead. If your compiler is that or newer, definitely file a bug report. -Steve It's a compile error, and it says that one should use alias as well. I was just surprised and I hadn't thought of why this alias would be needed. Based on the recommendation I found the language documentation, but there was no link to the article explaining the rationale. But I'm glad I read that article, it makes a lot more sense now.
What is the Utility of Parent Class Method Hiding in Inheritance?
https://dlang.org/spec/function.html#function-inheritance Consider this snippet from the documentation: class A { int foo(int x) { ... } int foo(long y) { ... } } class B : A { override int foo(long x) { ... } } void test() { B b = new B(); b.foo(1); // calls B.foo(long), since A.foo(int) not considered A a = b; a.foo(1); // issues runtime error (instead of calling A.foo(int)) } I ran into this the other day, where I had a function of the same name in a child class, and found that all functions in the parent of the same name now became hidden, unless I add an alias statement. After a bit of reading, I understood the rule and how it works, but what I'm missing is the "why". Why is it desirable to hide methods from a parent class which have the same name (but different arguments) as a method in a class?
Re: Converting an integer to a string with std.format.
On Sunday, 6 January 2019 at 21:53:31 UTC, Per Nordlöw wrote: When converting a single integer to a string is `formatValue` preferred over `formattedWrite` in terms of compilation and run-time performance? Also, if you do not need to write to a stream or a range and just need the value, `format("%s", value)` works as well as std.conv's `to!string(value)`. But between the two functions, it seems that the only difference is that `formattedWrite` only accepts the exact values that go on the output range (such as an integer), and `formatValue` has extra logic to convert structs, classes, and unions into strings by calling their `toString()` method.
Re: Best Way to Pass Template Typed Alias Parameters for Functions?
On Sunday, 23 December 2018 at 19:10:06 UTC, Alex wrote: On Sunday, 23 December 2018 at 18:53:15 UTC, Vijay Nayar wrote: You're right, it does compile. I'm a bit surprised. I wonder if this is a relatively recent improvement in the language, because last time I ran into this I had no such luck. But after seeing that your example did work, I figured one could try to get the best of both worlds by using a strongly-typed wrapper function in one's class. So far it seems to work: import std.traits; class A(KeyT, alias HashF) { // Strongly-typed wrapper around template value parameter 'HashF'. static size_t hash(in KeyT key) { return HashF(key); } static this() { static assert(isCallable!HashF, "Hash function is not callable!"); static assert(Parameters!(HashF).length == 1, "Hash function must take 1 argument."); static assert(is(Parameters!(HashF)[0] : const(KeyT)), "Hash parameter must be const."); static assert(is(typeof(HashF(KeyT.init)) : size_t), "Hash function must return size_t type."); } KeyT data; size_t getHash() const { return hash(data); } } void main() { auto a = new A!(int, (int a) => cast(size_t) a); a.data = 5; a.getHash(); } I'm not sure, whether you need the static this() part at all, as all of the asserts the compiler should do even when they are absent... by isCallable you restrict the HashF to not use IFTI by calling HashF(key) you ensure implicitely, that Parameters!(HashF).length == 1 by having hash(in KeyT key) defined with an "in" you ensured, that HashF does not mutate the argument and by defining size_t getHash() you ensured the return type of HashF... You are correct again! Playing around with using classes and functions returning the wrong type or not having a const argument, it seems that the compiler will assure that all the conditions needed by the wrapper function are satisfied and give a clear error. I don't know when this happened, but this definitely makes the language a lot easier to use for these circumstances, and all the std.traits stuff in "static this()" can be thrown out.
Re: Best Way to Pass Template Typed Alias Parameters for Functions?
On Sunday, 23 December 2018 at 18:31:24 UTC, Alex wrote: On Sunday, 23 December 2018 at 18:13:25 UTC, Vijay Nayar wrote: For example, if you have a const function in your container like "T find() const", and this function needs to use that comparator, then you're out of luck because the compiler doesn't know that the comparator function is const and will not modify the objects being compared. Last time I ran into this problem, my solution was simply to give up on const. But now I'm running into it again and trying to think through it again before giving up again. Hm... still not sure... ;) This would compile and run: ´´´ import std.experimental.all; size_t myHashFunction(int a) { return cast(size_t) a; } void main() { auto b = new B!(int, myHashFunction); b.arr = 42.iota.array; assert(b.find == 1); } class B(T, alias HashF) { T[] arr; T find() const { foreach(el; arr) { if(HashF(el)) { return el; } } assert(0); } } ´´´ You're right, it does compile. I'm a bit surprised. I wonder if this is a relatively recent improvement in the language, because last time I ran into this I had no such luck. But after seeing that your example did work, I figured one could try to get the best of both worlds by using a strongly-typed wrapper function in one's class. So far it seems to work: import std.traits; class A(KeyT, alias HashF) { // Strongly-typed wrapper around template value parameter 'HashF'. static size_t hash(in KeyT key) { return HashF(key); } static this() { static assert(isCallable!HashF, "Hash function is not callable!"); static assert(Parameters!(HashF).length == 1, "Hash function must take 1 argument."); static assert(is(Parameters!(HashF)[0] : const(KeyT)), "Hash parameter must be const."); static assert(is(typeof(HashF(KeyT.init)) : size_t), "Hash function must return size_t type."); } KeyT data; size_t getHash() const { return hash(data); } } void main() { auto a = new A!(int, (int a) => cast(size_t) a); a.data = 5; a.getHash(); }
Re: Best Way to Pass Template Typed Alias Parameters for Functions?
On Sunday, 23 December 2018 at 18:04:32 UTC, Alex wrote: On Sunday, 23 December 2018 at 17:13:49 UTC, Vijay Nayar wrote: I have a few cases where I would like to pass in a function as a value to a template, but I want to ensure that the function takes certain kinds of parameters, is a const function, or matches any other set of conditions. I assume you are looking for constraints... https://dlang.org/concepts.html Then, case B is the way to go, see https://run.dlang.io/is/jWU3tr Case D also looks promising. Not sure, how to formulate the specialization right now... There are a lot of traits you can use for the constraints. https://dlang.org/phobos/std_traits.html and https://dlang.org/spec/traits.html e.g., for constness there is getFunctionAttributes, which could be useful. I've been playing with the idea of specifying the constraints or using "static assert" in the constructor. They are good options, but there's a few cases where they fall a bit short. For example, imagine you have a container class that needs a comparator function to be able to compare the items in the container. While you can use std.traits to assure the right kind of function is passed in, that information does not make its way into the type system. For example, if you have a const function in your container like "T find() const", and this function needs to use that comparator, then you're out of luck because the compiler doesn't know that the comparator function is const and will not modify the objects being compared. Last time I ran into this problem, my solution was simply to give up on const. But now I'm running into it again and trying to think through it again before giving up again.
Best Way to Pass Template Typed Alias Parameters for Functions?
I have a few cases where I would like to pass in a function as a value to a template, but I want to ensure that the function takes certain kinds of parameters, is a const function, or matches any other set of conditions. What is the best way to do this? Just to avoid any potential confusion, I've included a few examples below. I'm using explicit functions rather than lambdas just avoid any possibility of types being incorrectly inferred. size_t myHashFunction(int a) { return cast(size_t) a; } void main() { class A(KeyT, HashF) { } auto a = new A!(int, myHashFunction); // ^ onlineapp.d: Error: template instance `A!(int, myHashFunction)` // does not match template declaration `A(KeyT, HashF)` // Alias parameter: https://dlang.org/spec/template.html#aliasparameters class B(KeyT, alias HashF) { } auto b = new B!(int, myHashFunction); // ^ Works, but we cannot enforce the kind of function passed in. // Typed alias parameter: https://dlang.org/spec/template.html#typed_alias_op class C(KeyT, alias size_t function(KeyT) HashF) { } auto c = new C!(int, myHashFunction); // ^ onlineapp.d: Error: template instance `C!(int, myHashFunction)` // does not match template declaration `C(KeyT, alias size_t function(KeyT) HashF)` // Specialization: https://dlang.org/spec/template.html#alias_parameter_specialization class D(KeyT, alias HashF : size_t function(KeyT)) { } auto d = new D!(int, myHashFunction // ^ onlineapp.d: Error: template instance `D!(int, myHashFunction)` // does not match template declaration `D(KeyT, alias HashF : size_t function(KeyT))` } Looking at some of the code in std.algorithm, it seem that static asserts are sometimes used for this purpose. Does anyone have a solution to this problem of instantiating template classes whose parameters are functions? I have used std.function "unaryFun" before, but this has the problem of not being able to specify function attributes, like const.
Re: How do you debug @safe @nogc code? Can't figure out how to print.
On Sunday, 18 November 2018 at 11:00:26 UTC, aliak wrote: On Saturday, 17 November 2018 at 21:56:23 UTC, Neia Neutuladh wrote: On Sat, 17 Nov 2018 21:16:13 +, aliak wrote: [...] 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! Alternatively, you can use the core.stc libraries, which do not depend on the GC, for debugging. https://dlang.org/phobos/core_stdc_stdio.html#.printf
Re: assigment to null class object member compiled? is this a bug?
On Friday, 19 October 2018 at 06:53:32 UTC, dangbinghoo wrote: hi, why the code bellow compiles? --- import std.stdio; class A { int m; } void main() { A a; a.m = 1; } --- and running this code get: `segmentation fault (core dumped) ./test` I consider this couldn't be compiled according to book Programming Language>. The latest dmd (2.082) and LDC2 behaves the same. Technically the code you have is syntactically correct. You are permitted to create a class variable without assigning it to a class object. (Assigning it to a class object would look like "A a = new A();") Which section of The D Programming Language book makes you think this would not compile? I have the book as well, but I'm not quite sure what part of the book you're referring to.
Re: Can Scope Be Used for Anonymous Objects?
On Wednesday, 17 October 2018 at 20:41:24 UTC, Ali Çehreli wrote: On 10/17/2018 01:24 PM, Vijay Nayar wrote: I have a snippet of code like this: scope chordAngle = new S1ChordAngle(_center, other._center); return _radius + other._radius >= chordAngle; The reason the "scope" temporary variable exists is to avoid a heap allocation and instead prefer a value be created on the stack. Is there a way to do this inline? Something like: return _radius + other._radius >= scope new S1ChordAngle(_center, other._center); I think it's possible but what you're looking for is std.typecons.scoped. 'scope' does not do what you think it does. import std.typecons : scoped; class C { int i; this(int i) { this.i = i; } int foo() { return i; } } bool bar() { auto c = scoped!C(42); return 42 == c.foo(); } bool bar_2() { return 42 == scoped!C(42).foo(); } void main() { bar(); bar_2(); } Ali This particular use of "scope" I overheard at the last DConf, and I believe it has been added to the official documentation here: https://dlang.org/spec/expression.html#new_expressions If a NewExpression is used as an initializer for a function local variable with scope storage class, and the ArgumentList to new is empty, then the instance is allocated on the stack rather than the heap or using the class specific allocator. I didn't know about the std.typecons scoped, it looks really useful, especially when you want to only create the object when short-circuiting fails, like in the middle of an "||" expression. One drawback of "scoped", however, is that it doesn't appear to warn you if you accidentally let the reference escape out of the function, unlike a scope variable.
Re: Can Scope Be Used for Anonymous Objects?
On Wednesday, 17 October 2018 at 20:51:29 UTC, Stanislav Blinov wrote: On Wednesday, 17 October 2018 at 20:24:56 UTC, Vijay Nayar wrote: I have a snippet of code like this: scope chordAngle = new S1ChordAngle(_center, other._center); return _radius + other._radius >= chordAngle; The reason the "scope" temporary variable exists is to avoid a heap allocation and instead prefer a value be created on the stack. Is there a way to do this inline? Why, exactly, is a trivial thing like this even a class? Porting C++ code which unfortunately makes heavy use of inheritance. I originally had this as a struct until I much later stumbled into the other classes that were inheriting from it.
Can Scope Be Used for Anonymous Objects?
I have a snippet of code like this: scope chordAngle = new S1ChordAngle(_center, other._center); return _radius + other._radius >= chordAngle; The reason the "scope" temporary variable exists is to avoid a heap allocation and instead prefer a value be created on the stack. Is there a way to do this inline? Something like: return _radius + other._radius >= scope new S1ChordAngle(_center, other._center);
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 11:11:09 UTC, Nicholas Wilson wrote: On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote: Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? Alex has mentioned Rebindable, which is the answer to your first question. To answer your second question, no class A {} A a: `a` is always a (possibly null) reference to a class instance. You can have pointers to class references (which is what `&a` gives you) but that has two indirections between the variable and the data, which if you want high perf is probably not what you are looking for. Thanks everyone for the insight. I also finished reading Jonathan's article: http://jmdavisprog.com/articles/why-const-sucks.html I've run into just about every single problem described there, but had no idea just how deep the problem goes. So it was a depressing read, but I'm glad to have the deeper understanding. I'm definitely more open now to see what "__mutable" could offer as was discussed at DConf2018, though I'm curious about how it would remain compatible with "immutable".
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 10:28:25 UTC, Alex wrote: On Sunday, 30 September 2018 at 09:30:38 UTC, Vijay Nayar wrote: Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? I think, what you are facing here, is the different notion of const, as used from C++. The reasoning about it is described for example here: http://jmdavisprog.com/articles/why-const-sucks.html Jonathan is much better therein as I am. However, there are approaches to solve what you want to do. For example, there is a Rebindable around: https://dlang.org/library/std/typecons/rebindable.html ´´´ import std.stdio; import std.typecons; void main() { class Thing {int dummy; } class ThingSaver { /* A const(Thing) could not be changed in setThing(), but a Rebindable can be reassigned, keeping t const. */ Rebindable!(const Thing) t; void setThing(in Thing thing) { t = thing; // No pointers in use :) } const(Thing) getThing() const { return t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); //saver.t.dummy = 5; fails as expected. const(Thing) t2 = saver.getThing(); } ´´´ I hope, I got your idea right... That pretty much hits the nail on the head, and you're exactly right about where my understanding was coming from (C++). In fact, I'm moving a lot of code from C++ to D and finding equivalents for a lot of high-performance index classes, which end up using this kind of pattern. Now I need to take the time to grok this article!
Re: New With Struct and Getting Class Object Pointers
On Sunday, 30 September 2018 at 09:16:42 UTC, Nicholas Wilson wrote: On Sunday, 30 September 2018 at 07:29:00 UTC, Vijay Nayar wrote: Second question. const class variables may not be re-assigned, so if you need a variable that may be reassigned, but may never modify the underlying object, a const pointer can be useful. However, it seems that when gets the address of a class variable, you do not get the underlying address of the class object. &a = 0x7ffd0800acb8, a = 0x7fd6b05b, a.data=4 &a = 0x7ffd0800acd0, a = 0x7fd6b05b, a.data=4 The stack ^ the heap^data on the heap^ The address of the variable a on the stack has different values across function calls, its value (the reference to the class data) remains the same, as does the data itself. Is there a way to either have a constant reference to a class that can be set to a new value, or is there a way to convert the class variable to a class pointer? For example: void main() { class Thing {} class ThingSaver { // A const(Thing) could not be changed in setThing(). const(Thing)* t; void setThing(in Thing thing) { t = thing; // ERROR converting to pointer type! } const(Thing) getThing() const { return *t; } } Thing t1 = new Thing(); ThingSaver saver = new ThingSaver(); saver.setThing(t1); const(Thing) t2 = saver.getThing(); }
New With Struct and Getting Class Object Pointers
I have two brief questions. Code that uses "new" to create struct objects appears to compile and run. Is this an actual language feature, to get structs on the heap? void main() { struct S {int data = 1;} S* s1 = new S(); S* s2 = s1; S s3 = *s1; // Still copies on assignment. s3.data = 2; assert(s1.data != s3.data); } Second question. const class variables may not be re-assigned, so if you need a variable that may be reassigned, but may never modify the underlying object, a const pointer can be useful. However, it seems that when gets the address of a class variable, you do not get the underlying address of the class object. How do you get a pointer to the underlying class object? Example of the problem: void main() { import std.stdio; class A { int data = 3; } A a = new A(); void f(A a) { a.data = 4; writeln("&a = ", &a, ", a.data = ", a.data); } f(a); writeln("&a = ", &a, ", a.data = ", a.data); } // Output: &a = 7FFEA6BA3158, a.data = 4 // Addresses are different, from different class variables. &a = 7FFEA6BA3180, a.data = 4 // But the same underlying class object. Especially if I'm several levels down the call stack, how do I get a pointer to the underlying class object?
Preferred Alias Declaration Style
Most of the documentation at https://dlang.org/spec/declaration.html#alias uses examples of the form: `alias aliasName = other;`, where `aliasName` becomes the new name to reference `other`. Alternatively, one may write `alias other aliasName;`. My understanding is that the syntax with `=` is the preferred one stylistically. However, when it comes to `alias this` declarations, the only syntax supported is `alias other this;`, and one cannot write `alias this = other;`. Does this mean that the `alias other aliasName;` syntax is preferred, or does it simply mean that this is a low priority issue that hasn't been addressed yet?
range.put() to Empty Array Causes Error?
This code breaks with the following error: void main() { import std.range; int[] vals = []; vals.put(3); } /src/phobos/std/range/primitives.d(2328): Attempting to fetch the front of an empty array of int The following code has no error: void main() { import std.range; int[] vals = [1]; vals.put(3); } Why is range.put() not allowed for empty arrays?
Re: Implicit Template Parameters Cannot Decipher Aliases?
On Wednesday, 25 April 2018 at 10:25:11 UTC, Simen Kjærås wrote: In the general case, the issue is unsolvable, since the relationship between template parameters and alias results may be arbitrarily complex. A simple degenerate case is this: Ok, wow, you weren't kidding. That becomes really complex really fast. In that case, is the general rule of thumb that programmers should not use aliases for templated types when specifying template function parameters? No implicit type inference is done on the return type or on local variables, so these alias seem fine enough there. Or should they just be entirely avoided to avoid these kinds of problems?
Re: Implicit Template Parameters Cannot Decipher Aliases?
On Wednesday, 25 April 2018 at 07:39:28 UTC, Vijay Nayar wrote: addAllWithAlias(v1); // Error! One more note, this following line works correctly. addAllWithAlias!double(v1); // OK.
Implicit Template Parameters Cannot Decipher Aliases?
I have encountered a problem where whenever I attempt to use a templated function with alias that partially limits the type of the arguments, the program fails to compile. But if I avoid using an alias, the same function can infer all arguments. Is this working as intended or have I encountered a bug or missing feature? Example below: ``` /** * Demonstrate an unexpected compiler error when using implicit template parameters * combined with aliases to partially instantiate templates. */ struct Vector(ElemT, size_t SizeV) { private: ElemT[SizeV] _data; public: @property ElemT[SizeV] data() { return _data; } ElemT opIndex(size_t i) { return _data[i]; } } // A helper alias to partially set a portion of compile-time arguments. template Vector3(ElemT) { alias Vector3 = Vector!(ElemT, 3); } T addAllWithAlias(T)(Vector3!T v1) { T sum = 0; foreach (T v; v1.data) { sum += v; } return sum; } T addAll(T)(Vector!(T, 3) v1) { T sum = 0; foreach (T v; v1.data) { sum += v; } return sum; } void main() { auto v1 = Vector3!double([1.0, 2.0, 3.0]); assert(v1[1] == 2.0); addAllWithAlias(v1); // Error! // template.d(35): Error: template template.addAllWithAlias cannot deduce function from // argument types !()(Vector!(double, 3LU)), candidates are: // template.d(24): template.addAllWithAlias(T)(Vector3!T v1) addAll(v1); // OK. } ```