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: Builder: Tiny Utility Library to Add a Builder API to Classes
On Friday, 6 January 2023 at 09:26:51 UTC, thebluepandabear wrote: .isActive(true) .build(); ``` Good how would I extend the builder methods? The builder methods are automatically generated and go up the inheritance chain to capture all the fields in your class. (I assume that you are referring to inheritance when you say "extend"?) Here is one of the unit-tests demonstrating this: ``` class A2 { int a; string b; } class B2 : A2 { int c; mixin AddBuilder!(typeof(this)); } /// All inherited fields should be available from the builder. unittest { B2 b2 = B2.builder() .a(3) .b("ham") .c(4) .build(); assert(b2.a == 3); assert(b2.b == "ham"); assert(b2.c == 4); } ```
Re: Builder: Tiny Utility Library to Add a Builder API to Classes
On Thursday, 5 January 2023 at 23:31:36 UTC, Vladimir Marchevsky wrote: On Thursday, 5 January 2023 at 21:48:40 UTC, Vijay Nayar wrote: 2. Using a constructor with many arguments. ``` A a = new A("Bob", 20, false, true); ``` This approach can construct arguments inline, such as during a function call, however, the arguments are not labeled, making it easy to get the order wrong or for the meaning to be unclear. Hopefully we'll finally have named arguments. Considering they were accepted to language more than two years ago - maybe in the next century... Named arguments would definitely obviate this tool, but in the meanwhile, this tool basically lets you achieve the same objectives in terms of single-expression construction and clearly labeled arguments. I guess one extra advantage of the `builder` library is that you also don't have to bother writing a constructor at all and can just use the default one.
Builder: Tiny Utility Library to Add a Builder API to Classes
https://code.dlang.org/packages/builder Interacting with many projects that are related to Java, I could not help notice that a common "Builder API" is not easily available in D. What is the problem? When constructing classes, especially those with lots of data, there are two broad ways of building the object. 1. Initializing each field in a different statement. ``` A a = new A(); a.setName("Bob"); a.setAge(20); a.isProbation(false); a.isActive(true); ... ``` This approach involves writing a lot of boiler plate, and it doesn't work well for quickly creating objects inline, such as during a function call. 2. Using a constructor with many arguments. ``` A a = new A("Bob", 20, false, true); ``` This approach can construct arguments inline, such as during a function call, however, the arguments are not labeled, making it easy to get the order wrong or for the meaning to be unclear. This library allows one to get the best of both worlds. Construction within a single statement, but also without losing meaning of the parameters, e.g. ``` class A { string name; int age; bool isProbation; bool isActive; mixin AddBuilder!(typeof(this)); } A a = A.builder() .name("Bob") .age(20) .isProbation(false) .isActive(true) .build(); ```
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?
OpenAPI Client Generator
I would like to put an announcement for two new projects added to https://code.dlang.org. https://code.dlang.org/packages/openapi-client This project is an executable that reads an [OpenAPI Specification](https://spec.openapis.org/oas/latest.html) in JSON format and writes a D client to interact with the described REST API. https://code.dlang.org/packages/stripe-client This project contains code produced by the `openapi-client` project to provide an interface to [Stripe](https://stripe.com/en-de), which is a service that allows one to make and receive online payments using a wide variety of methods, ranging from Credit Cards, to bank transfers, to even invoices. Usage of the client libraries generated by `openapi-client` follows a similar pattern: 1. "Service" classes represent groups of related API Endpoints by URL. 2. Each method of a "Service" class corresponds to a single API Endpoint. 3. The methods generally take up to 3 arguments: - Parameters: These ultimately translate into path, header, cookie, or query-string parameters of the endpoint, depending on the OpenAPI Specification. - RequestBody: This corresponds to the uploaded HTTP request body for POST or PUT requests. - ResponseHandler: A object to set typed `delegates` to handle endpoint responses. The types may vary depending on the status code, e.g. a `200 OK` might process a `ChargeList` argument, but a `400 NOT FOUND` response might provide an `Error_` argument instead. Example code: ``` import stripe.security : Security; import stripe.service.v1_charges_service : V1ChargesService; import vibe.data.json : serializeToJsonString; // 1. Stripe's OpenAPI specification has two valid security schemes: // - HTTP Basic Auth (named "BasicAuth") // - HTTP Bearer Auth (named "BearerAuth") Security.configureBasicAuth( "sk_test_51MFbD...vri", // Username / API key ""); // With Stripe, the password is always blank. // 2. Service classes are created from valid URL paths + "Service", e.g. "/v1/charges" => "V1ChargesService". auto service = new V1ChargesService(); // 3. Each endpoint has a "Params" object which covers any path, query-string, header, or cookie parameters. auto params = new V1ChargesService.GetChargesParams(); // 4. Some requests have a request body, which will be an argument to the method, // e.g. "postCharges(params, requestBody, handler)". // 5. Different HTTP status codes can be associated with different data types. // Create a handler object and add your own delegates that say what to do with each response. auto handler = new V1ChargesService.GetChargesResponseHandler(); // 6. This handler is for a successful 200 response, there's also a default handler for errors. handler.handleResponse200 = (V1ChargesService.GetChargesResponseHandler.ChargeList chargeList) { // Simply print out our response in JSON format. writeln(serializeToJsonString(chargeList)); }; // 7. Now call the desired endpoint and your handler will be invoked depending on the response. service.getCharges(params, handler); ``` Feedback is always welcome, or bugs can be reported on each project's GitHub Issues.
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 v0.9.5 released!
On Monday, 18 July 2022 at 16:07:02 UTC, Mathias LANG wrote: Hi everyone, A new version of Vibe.d has been released today. You can see the list of changes [on Github](https://github.com/vibe-d/vibe.d/releases/tag/v0.9.5). Of particular interest to me is the bump of the deimos/OpenSSL dependency to v3.x.x. Great news! I've definitely run into the SSL configuration issues before, and this should help make Vibe.d adoption easier for new users.
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: Release: avro-d v0.1.0
On Wednesday, 9 March 2022 at 14:26:10 UTC, Vijay Nayar wrote: The initial v0.1.0 of the Avro library in D can be found here: https://code.dlang.org/packages/avro-d Version 0.2.2 has been released, which includes the ability to read and write generic objects in JSON format in addition to the aforementioned binary format.
Release: avro-d v0.1.0
Greetings D Community, Do you have need for an efficient binary format for encoding and decoding data, but are hesitant to use things like [Google Protocol Buffers](https://developers.google.com/protocol-buffers) due to the need to re-compile code in order to change formats? [Apache Avro](https://avro.apache.org/docs/current/) addresses many of these problems by pairing a binary (and other) format with a JSON formatted schema which is part of the protocol. Sadly, this protocol is not available in the D Programming language... until now. The initial v0.1.0 of the Avro library in D can be found here: https://code.dlang.org/packages/avro-d ## Features Implemented ### Schema representation A set of data classes exist to represent schemas for generation in code or the processing of data. For example: ```d import avro.schema; auto schema = new UnionSchema([ Schema.createPrimitive(Type.STRING), Schema.createPrimitive(Type.INT)]); ``` ### Schema parsing & validation Schemas may be parsed from files, text, or JSON. For example: ```d import avro.parser; auto parser = new Parser(); Schema schema = parser.parseText(q"EOS {"namespace": "example.avro", "type": "record", "name": "User", "fields": [ {"name": "name", "type": "string"}, {"name": "favorite_number", "type": ["int", "null"]}, {"name": "favorite_color", "type": ["string", "null"]} ] } EOS"); ``` Errors in the JSON format of a schema will lead to descriptive errors. ### Generic Data types Generic data objects may be created according to schemas with their values set to schema-appropriate defaults and validation logic when setting values. Most `GenericDatum` objects make use of `.getValue!T()` and `.setValue(T)(T val)` methods, however, many convenience functions also exist. For example: ```d import avro.generic.genericdata; // Initializes the GenericDatum according to the schema with default values. GenericDatum datum = new GenericDatum(schema); assert(datum.getType == Type.RECORD); // Primitive values can be set and retrieved. datum.getValue!(GenericRecord).getField("name").setValue("bob"); // Convenience shortcut using opIndex() and opAssign() for primitive types. datum["name"] = "bob"; assert(datum["name"].getValue!string == "bob"); // Enums have convenience functions directly on GenericData. datum["favorite_number"].setUnionIndex(0); assert(datum["favorite_number"].getUnionIndex() == 0); // Arrays also have convenience functions. datum["scores"] ~= 1.23f; datum["scores"] ~= 4.56f; assert(datum["scores"].length == 2); p // Maps do as well. datum["m"]["m1"] = 10L; datum["m"]["m2"] = 20L; assert(datum["m"]["m1"].getValue!long == 10L); ``` ### Binary Serialization/Deserialization `GenericData` objects can be written using an encoder. For example: ```d import avro.codec.binaryencoder; import avro.generic.genericwriter; ubyte[] data; auto encoder = binaryEncoder(appender()); GenericWriter writer = new GenericWriter(schema, encoder); writer.write(datum); assert(data == [ // Field: name // len=3 b o b 0x06, 0x62, 0x6F, 0x62, // Field: favorite_number // idx=0 8 0x00, 0x10, // Field: favorite_color // idx=0 len=4 b l u e 0x00, 0x08, 0x62, 0x6C, 0x75, 0x65 ]); ``` They may also be read using a decoder. For example: ```d import avro.codec.binarydecoder; import avro.generic.genericreader; auto decoder = binaryDecoder(data); GenericReader reader = new GenericReader(schema, decoder); GenericDatum datum; reader.read(datum); assert(datum["name"].getValue!string() == "bob"); assert(datum["favorite_number"].getValue!int() == 8); assert(datum["favorite_color"].getValue!string() == "blue"); ``` ## Features Not Yet Implemented - Logical Type support - Specific Data types generated for schemas - JSON Serialization/Deserialization - Codex compression support - Object Container Files - Protocol wire format - Schema Resolution
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: The ABC's of Templates in D
On Friday, 31 July 2020 at 13:46:43 UTC, Mike Parker wrote: The blog: https://dlang.org/blog/2020/07/31/the-abcs-of-templates-in-d/ This is very well written! I want to share it with my coworkers using Java to see if it piques their interest.
Re: Searching for Dgame Maintainer
On Sunday, 24 November 2019 at 16:34:35 UTC, Dgame wrote: Maybe some of you know Dgame (https://github.com/Dgame/Dgame), it was my biggest project using D and was a lot of fun at that time. But since I don't use D anymore, I have neither the time nor the desire and even less the knowledge to take care of it anymore. So, if anyone wants to keep it going, I am open for offers. I have never used Dgame before, but what immediately stands out is that it's pretty well organized. Your website also does a great job at explaining how to use the library and the tutorials are well done. There is even a style guide for contributors. It really seems that quite a bit of work and care went into making this. I am curious to know why you are no longer using D? Is it more that personal and professional life has taken up your free time, or have you found something else where you would prefer to invest your time and energy? Or was it something about the D language or community that initiated the change?
Re: S2Geometry Library Release v0.2
On Saturday, 25 May 2019 at 19:34:50 UTC, Sebastiaan Koppe wrote: On Saturday, 25 May 2019 at 11:48:12 UTC, Vijay Nayar wrote: D's philosophy of having a large tool-box makes this work doable by a single person while other languages have spent many years with many contributors. Great work! Can you tell something about how you converted the code and how you plan to stay up-to-date? I would say that this library is a bit of a special case in most regards. The code base is quite complicated not only in subject matter and mathematics, but also in the actual dependencies between modules as well. The code itself has numerous circular dependencies, but when you factor in the unit-tests as well, the case becomes much more severe. The original code also passes around references to stack objects frequently, and manual changes had to be made to replace that logic. This will give C++ a slight edge in performance, but I think the gain in safety is worth it. The actual conversion was entirely by hand, making appropriate replacements for many parts of the algorithms. Where the original logic became nearly impossibly complex to understand, debugging was mostly done by following this procedure: 1. Find a failing test. 2. Instrument the D code with print statements leading up to the failing logic. 3. Instrument the C++ code with the equivalent print statements. 4. Run both tests and compare the output. 5. Add more print statements if there are no differences or if the code is not yet identified. 6. Cleanup. If that approach sounds kinda silly, it's because it is. However, what it means is that the library is actually capable of being converted into D without me having to get a PhD in mathematics first :P On the question of keeping the library up to date, this is also a bit of a special case. Previously I've used the Java version of this library which is already 8 years old, and it is extremely useful even today. The actual library itself is fairly complete, and even if it were to never get another update, it would continue to be very useful for a long time.
Re: S2Geometry Library Release v0.2
On Saturday, 25 May 2019 at 11:48:12 UTC, Vijay Nayar wrote: I wanted to announce here the v0.2 release of the S2 Geometry Library in the D language. The DUB page should be updated to show v0.2 shortly. https://code.dlang.org/packages/s2geometry-d Today I learned that released versions must be 3 digits in order to be picked up by DUB. The release is now v0.2.0.
S2Geometry Library Release v0.2
Greetings everyone. I wanted to announce here the v0.2 release of the S2 Geometry Library in the D language. The DUB page should be updated to show v0.2 shortly. https://code.dlang.org/packages/s2geometry-d What is it? = The S2 Geometry library is an extremely high precision and performant library for geometry on the surface of the Earth. It is useful for dealing with areas, boundaries, lines, polygons, etc. As a practical example, it can answer very quickly if thousands of driving paths would pass through the arbitrary boundaries of an airport and thus need to pay a toll. It was originally created by Eric Veach and the library is used in Google. I have converted this library in the D programming language. What's New? = This release is now nearly feature complete with the C++ library. Only encoding/decoding of geometric objects is missing. What's in Store Next? * More work is needed to improve performance further. The full D test suite runs in 139 seconds while the C++ full test suite only needs 112 seconds. * Encoding/Decoding support for transmitting geometric objects in binary form. * Work on this library will slow down, as I plan to start using it instead of writing it. Why does this matter? Currently only C++ and D have this level of feature support, which cannot be found in Java, Python, Go, Rust, or any other languages today. Part of the reason for this is that it's a very very very large and complex project that makes use of a large set of C++ features. --- Language filesblank comment code --- C++ 177 60821282037378 C/C++ Header 164 63851869121935 Python 1 35 24 188 CMake 100 16 --- SUM: 343125023153559517 --- D's philosophy of having a large tool-box makes this work doable by a single person while other languages have spent many years with many contributors.
Re: LDC 1.15.0
On Saturday, 6 April 2019 at 17:40:39 UTC, kinke wrote: Glad to announce LDC 1.15: * Based on D 2.085.1. * Support for LLVM 8.0. The prebuilt packages ship with LLVM 8.0.0 and include the Khronos SPIRV-LLVM-Translator, so that dcompute can now emit OpenCL too. * New -lowmem switch to enable the GC for the front-end, trading compile times for less required memory (in some cases, by more than 60%). * New generic @llvmAttr("name") parameter UDAs, incl. @restrict with C-like semantics. * Dropped support for 32-bit macOS. Min macOS version for prebuilt package raised to 10.9. * Prebuilt packages don't depend on libtinfo/libedit and don't require SSSE3 anymore. * Fix: functions annotated with `pragma(inline, true)` are implicitly cross-module-inlined again. Full release log and downloads: https://github.com/ldc-developers/ldc/releases/tag/v1.15.0 Thanks to all contributors! Pretty amazing work! I especially like the -lowmem option, which actually solves the problem of certain compile-time heavy algorithms failing to compile entirely due to running out of memory.
Re: DIP 1000--Scoped Pointers--Superseded
On Thursday, 7 March 2019 at 11:30:01 UTC, Mike Parker wrote: As most of you surely know, DIP 1000, "Scoped Pointers", has been sitting in the DIP queue with the Draft status for ages and was significantly out of sync with the implementation. When I first took over as DIP Manager, the initial plan was to rewrite the DIP to match the implementation once the implementation had stabilized. I asked Walter about it recently and he agreed that, at this point, the "Superseded" status would be appropriate for this DIP. It was introduced when an implementation of DIP 1006 was implemented that differed from the proposal. The circumstances for DIP 1000 are similar, though perhaps more extreme. So DIP 1000 is now branded "Superseded". https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md What is it superseded by? Is there another DIP that supersedes the concept or implementation?
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: The New Fundraising Campaign
On Wednesday, 2 January 2019 at 13:30:34 UTC, Martin Tschierschke wrote: On Wednesday, 2 January 2019 at 13:07:23 UTC, Joakim Brännström wrote: On Wednesday, 2 January 2019 at 10:16:11 UTC, Martin Tschierschke wrote: This campaign will end in 43 day, so the question after app. 50% is, what next? Will we start collecting for something else or should we first try to extend the job of our pull request manager? Thanks Martin for the reminder. From my observations of the activities on github it seems like Nicholas Wilson is doing an excellent job :-) Regards, Joakim B. Thank you! So here an update of the update: $2,464 Raised of $3,000 Goal by 46 Supporters => We only need another 10 Supporters giving an average of $54. :-) For me the credit card payment method fails without saying what's wrong. Is there another method to pay, like a IBAN that a transfer could be made to?
Re: DCD, D-Scanner and DFMT : new year edition
On Monday, 31 December 2018 at 07:56:00 UTC, Basile B. wrote: DCD [1] 0.10.2 comes with bugfixes and small API changes. DFMT [2] and D-Scanner [3] with bugfixes too and all of the three products are based on d-parse 0.10.z, making life easier and the libraries versions more consistent for the D IDE and D IDE plugins developers. [1] https://github.com/dlang-community/DCD/releases/tag/v0.10.2 [2] https://github.com/dlang-community/dfmt/releases/tag/v0.9.0 [3] https://github.com/dlang-community/D-Scanner/releases/tag/v0.6.0 Really fantastic work! I typically use DCD integrated into Emacs via company-dcd-mode.
Re: DConf 2019: Shepherd's Pie Edition
On Saturday, 22 December 2018 at 12:18:25 UTC, Mike Parker wrote: Thanks to Symmetry Investments, DConf is heading to London! We're still ironing out the details, but I've been sitting on this for weeks and, now that we have a venue, I just can't keep quiet about it any longer. Looking forward to it! The caliber of people at these conferences has been exceptional every year I've gone, and many of the ideas presented have been very valuable, whether they were directly related to DLang or not. Just one small example was a 2017 talk by Bastiaan Veelo on D libraries implementing Parsing Expression Grammars, which I had never heard of at the time. But the idea ended up being very useful for greatly simplifying the interfaces of systems I was working on that year. I've been doing quite a bit of work this year on the Google S2 Geometric Library in D. If I can benchmark the library against the C++ version or show how it can be used to tackle some of the trickier real-time problems in large-scale web services, would it be a good candidate to try to make into a talk for the conference?
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: Blog post: What D got wrong
On Wednesday, 12 December 2018 at 07:44:12 UTC, Walter Bright wrote: On 12/11/2018 4:51 AM, Nicholas Wilson wrote: > Returning a reference Wow, thats f*ck'n stupid! https://run.dlang.io/is/SAplYw It's quite deliberate. ref in C++ is a type constructor, but it's so special-cased to behave like a storage class, it might as well be one. In D it is. (For example, ref in C++ can only appear at the top level. There are no "pointers to refs".) refs exist so the lifetime of them can be controlled for memory safety. Treating them as flexibly as pointers would make that pretty difficult. refs are the primary way a memory safe container can expose pointers to its contents. Could you please elaborate a little bit more on this? In the linked program, I had expected that "ref" would return a reference to "a" that would behave similar to a pointer. But when that reference is assigned to "b", and "b" is modified, "a" appears to retain its original value, implying that "b" is a copy. When was the copy of "a" made? Was it during the assignment to "b"? I use ref regularly, especially when I have to port C++ code that does exactly that, exposing modifiable references to its members. And in my experience it works quite well, especially for array types and classes. So what is the best way to understand this program and know why a copy of "a" is made?
S2 Geometric Library for D
I would like to announce the release of the S2 Geometric Library in the D Programming Language. Who: This is of interest to engineers who need to process very large amounts of geographic coordinate data very quickly. E.g. ride-shares, bikes, maps, etc. What: The S2 Geometric Library was originally developed by Eric Veach from Google to serve as a highly performance geo-spatial library with very high accuracy. It achieves this by keeping coordinates as 3D points which are projected onto the Earth's surface. http://s2geometry.io/ Where: DUB Package - https://code.dlang.org/packages/s2geometry-d When: Right now, the first version with most features is ready. The remaining features will be added in the following couple of months. Why: I have used the Java port of this library (https://github.com/google/s2-geometry-library-java) in systems handling thousands of inputs per second with great results. The Java version, however, is 7 years old, and because performance was my interest, I decided to port this library from it's modern C++ version to D. How: Lots and lots of work over a long time: https://github.com/vnayar/s2geometry-d/graphs/code-frequency
Re: Using D for AWS Beanstalk applications (German)
On Tuesday, 27 November 2018 at 21:39:42 UTC, Andre Pany wrote: Hi, Find here a short tutorial how you can directly execute D applications on AWS Beanstalk. http://d-land.sepany.de/tutorials/cloud/native-aws-beanstalk-applikation/ Kind regards Andre I would never have believed that it would be so easy to run a D application on AWS. Your description is very clear. Well done! Ich würde nie glaubt haben, dass es so einfach eine D-Anwendung auf AWS ausführen könnte. Ihren Beschreibung ist wirklich klar. Gut gemacht!
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: Shared - Another Thread
On Wednesday, 17 October 2018 at 21:12:49 UTC, Stefan Koch wrote: Hi, reading the other shared thread "shared - i need to be useful"(https://forum.dlang.org/thread/mailman.4299.1539629222.29801.digitalmar...@puremagic.com) let me to an important realisation concerning the reason shareding data across threads is so unintuitve and hard to get right. The reason is that sharing in the real world has nothing to do with using something and the same time. For example: If I share my flat with another person, that person, while occupying the same flat as me, cannot actually occupy the same space. It is physically impossible. In other words sharing does not mean for multiple entities to own something it's rather about diving and managing the (temporary) ownership of fragments. Therefore if ownership is unclear sharing is impossible. The safest default for something shared with unclear ownership is to view it as untouchable/unreadble/unwritable until ownership is established. My understanding is that the "shared" keyword can be useful especially with array types that are operated on by multiple threads. Some algorithms put together data following specific rules on how that data can be fragmented. Imagine a simple algorithm that does logic on very long numbers, split into bytes. One multi-threaded implementation may use 4 threads. The first operating on bytes 0, 4, 8, etc. The second operating on bytes 1, 5, 9, etc. In this case, a mutex or lock isn't actually needed, because the algorithm itself assures that threads don't collide. It's an over-simplification, but I think this is basically what the prime-number finding algorithm by Jabari Zakiya is doing.
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: A Friendly Challenge for D
On Monday, 15 October 2018 at 22:17:57 UTC, Jabari Zakiya wrote: $ dub build --compiler=ldc2 -b=release && echo "30" | ./twinprimes Enter integer number: threads = 8 each thread segment is [1 x 65536] bytes array twinprime candidates = 175324676; resgroups = 1298702 each 135 threads has nextp[2 x 5566] array setup time = 1 ms, 864 μs, and 7 hnsecs perform twinprimes ssoz sieve sieve time = 196 ms, 566 μs, and 5 hnsecs last segment = 53518 resgroups; segment slices = 20 total twins = 9210144; last twin = 299712+/- 1 total time = 198 ms, 431 μs, and 2 hnsecs My understanding is that the difference in performance is largely due to slightly better optimization from the LLVM based ldc2 compiler, where I believe Nim is using gcc. Here's what I get on my system. $ echo 3_000_000_000 | ./twinprimes_test7yc.0180.gcc821 Enter integer number: threads = 8 each thread segment is [1 x 65536] bytes array twinprime candidates = 175324676; resgroups = 1298702 each 135 threads has nextp[2 x 5566] array setup time = 0.000 secs perform twinprimes ssoz sieve sieve time = 0.144 secs last segment = 53518 resgroups; segment slices = 20 total twins = 9210144; last twin = 299712+/-1 total time = 0.144 secs Could you list your hardware, D ver, compiler specs. I will run your code on my system with your D version and compiler, if I can. Excellent work! D has multiple compilers, but for the speed of the finished binary, LDC2 is generally recommended. I used version 1.11.0. https://github.com/ldc-developers/ldc/releases/tag/v1.11.0 I was using DUB to manage the project, but to build the stand-alone file from the gist link, use this command: $ ldc2 -release -O3 twinprimes_ssoz.d And to run it: $ echo "30" | ./twinprimes_ssoz Running the program a bunch of times, I get variable results, mostly between 195ms and 250ms. Running the Nim version, I also get variable results, mostly between 230ms and 280ms. My system is an Alienware 14x R2 from 2012. Specs can be found here: https://www.cnet.com/products/alienware-m14xr2-14-core-i7-3630qm-8-gb-ram-750-gb-hdd/specs/
Re: A Friendly Challenge for D
On Sunday, 14 October 2018 at 10:51:11 UTC, Vijay Nayar wrote: Once I get the bugs out, I'm curious to see if any performance differences crop up. There's the theory that says they should be the same, and then there's the practice. I don't actually understand the underlying algorithm, but I at least understand the flow of the program and the structure. The algorithm utilized depends heavily on using shared memory access, which can be done in D, but I definitely wouldn't call it idiomatic. In D, message passing is preferred, but it really can't be well demonstrated on your algorithm without a deeper understanding of the algorithm itself. A complete working version can be found at: https://gist.github.com/vnayar/79e2d0a9850833b8859dd9f08997b4d7 I modified both versions of the program to utilize the pgParameters13 for more of an apples-to-apples comparison. The final results are as follows: $ nim c --cc:gcc --d:release --threads:on twinprimes_ssoz.nim && echo "30" | ./twinprimes_ssoz Enter integer number: threads = 8 each thread segment is [1 x 65536] bytes array twinprime candidates = 175324676; resgroups = 1298702 each 135 threads has nextp[2 x 5566] array setup time = 0.000 secs perform twinprimes ssoz sieve sieve time = 0.222 secs last segment = 53518 resgroups; segment slices = 20 total twins = 9210144; last twin = 299712+/-1 total time = 0.223 secs $ dub build --compiler=ldc2 -b=release && echo "30" | ./twinprimes Enter integer number: threads = 8 each thread segment is [1 x 65536] bytes array twinprime candidates = 175324676; resgroups = 1298702 each 135 threads has nextp[2 x 5566] array setup time = 1 ms, 864 μs, and 7 hnsecs perform twinprimes ssoz sieve sieve time = 196 ms, 566 μs, and 5 hnsecs last segment = 53518 resgroups; segment slices = 20 total twins = 9210144; last twin = 299712+/- 1 total time = 198 ms, 431 μs, and 2 hnsecs My understanding is that the difference in performance is largely due to slightly better optimization from the LLVM based ldc2 compiler, where I believe Nim is using gcc.
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 19:04:48 UTC, Jabari Zakiya wrote: On Saturday, 13 October 2018 at 18:31:57 UTC, Vijay Nayar wrote: On Saturday, 13 October 2018 at 18:14:20 UTC, Vijay Nayar wrote: On Saturday, 13 October 2018 at 18:05:45 UTC, Jabari Zakiya wrote: It may be also running into a hard time limit imposed on compilation that Nim had/has that prevented my code from initially compiling. I'm generating a lot of PG parameter constants at compile time, and it's doing a lot of number crunching and building larger and larger arrays of constants as the PG's get larger. Try compiling with successive PG's (just P5, then P5 and P7, etc) to see where it fails. That will let you know the code is working correctly, and that the compiler is choking either/and because of a hard time limit and/or memory limit. That's why I put in a compiler output statement in 'genPGparameters' to see the progression of the PG parameters being built by the compiler to initially find when the compiler started choking. You may also need to patch whatever facility in the D compiler chain that controls this too. It's P17, the biggest one that takes the longest to build in the Nim version. I actually don't know what memory limits exist for the D compiler at compile-time, so I may need to do some homework. It's not just DMD either. $ ldc2 twinprimes_ssoz.d ... generating parameters for P17 Killed $ gdc twinprimes_ssoz.d ... generating parameters for P17 gdc: internal compiler error: Killed (program cc1d) Please submit a full bug report, with preprocessed source if appropriate. See for instructions. $ dmd twinprimes_ssoz.d ... generating parameters for P17 Killed In the Nim code, starting line 91 is when the PG constants are being generate at compile time. - # Generate at compile time the parameters for PGs P5-P17. const parametersp5 = genPGparameters(5) const parametersp7 = genPGparameters(7) const parametersp11 = genPGparameters(11) const parametersp13 = genPGparameters(13) const parametersp17 = genPGparameters(17) - Can it compile just using P5 (the first line, others commented out), and then P7, etc? I'm not understanding your comments now. If you can get a working version up and running (with correct output) we can solve the P17 compiler issues later (or in a parallel forum thread), especially if you have to delve into the weeds of the compiler chain. In my mind (same with Nim process) getting working code using any PG is first order priority (because you'll need getting multi-threading working too). Once you can do that, by default, you can then use any generator you want if you create the correct parameters for it. That's one of the advantages of the algorithm, it's PG agnostic (as long as your hardware will accommodate it). So don't prioritize getting P17 to compile right now (in this thread). Create the working generic structure that can work with any PG first. Updated: https://gist.github.com/vnayar/79e2d0a9850833b8859dd9f08997b4d7 I still get a few runtime errors likely from mistakes in my conversion for certain primes. I'll resolve those after I get back from the gym. But as previous posters have said, the code is not really very different between Nim and D. Most of it is array manipulation and arithmetic operations, and not many of the features of either D or Nim are very different. Both turn into fast code, both have garbage collection, and both have generally similar operators and libraries for this kind of problem. The biggest differences I observed revolved not around the languages themselves, but around code style. For example, can you put a loop and 3 additional statements on a single line in D? Yes. But it is considered to be not very readable code from a style perspective. Once I get the bugs out, I'm curious to see if any performance differences crop up. There's the theory that says they should be the same, and then there's the practice.
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 18:14:20 UTC, Vijay Nayar wrote: On Saturday, 13 October 2018 at 18:05:45 UTC, Jabari Zakiya wrote: It may be also running into a hard time limit imposed on compilation that Nim had/has that prevented my code from initially compiling. I'm generating a lot of PG parameter constants at compile time, and it's doing a lot of number crunching and building larger and larger arrays of constants as the PG's get larger. Try compiling with successive PG's (just P5, then P5 and P7, etc) to see where it fails. That will let you know the code is working correctly, and that the compiler is choking either/and because of a hard time limit and/or memory limit. That's why I put in a compiler output statement in 'genPGparameters' to see the progression of the PG parameters being built by the compiler to initially find when the compiler started choking. You may also need to patch whatever facility in the D compiler chain that controls this too. It's P17, the biggest one that takes the longest to build in the Nim version. I actually don't know what memory limits exist for the D compiler at compile-time, so I may need to do some homework. It's not just DMD either. $ ldc2 twinprimes_ssoz.d ... generating parameters for P17 Killed $ gdc twinprimes_ssoz.d ... generating parameters for P17 gdc: internal compiler error: Killed (program cc1d) Please submit a full bug report, with preprocessed source if appropriate. See for instructions. $ dmd twinprimes_ssoz.d ... generating parameters for P17 Killed
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 18:05:45 UTC, Jabari Zakiya wrote: It may be also running into a hard time limit imposed on compilation that Nim had/has that prevented my code from initially compiling. I'm generating a lot of PG parameter constants at compile time, and it's doing a lot of number crunching and building larger and larger arrays of constants as the PG's get larger. Try compiling with successive PG's (just P5, then P5 and P7, etc) to see where it fails. That will let you know the code is working correctly, and that the compiler is choking either/and because of a hard time limit and/or memory limit. That's why I put in a compiler output statement in 'genPGparameters' to see the progression of the PG parameters being built by the compiler to initially find when the compiler started choking. You may also need to patch whatever facility in the D compiler chain that controls this too. It's P17, the biggest one that takes the longest to build in the Nim version. I actually don't know what memory limits exist for the D compiler at compile-time, so I may need to do some homework.
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 15:50:06 UTC, Vijay Nayar wrote: On Saturday, 13 October 2018 at 15:19:07 UTC, Jabari Zakiya wrote: On Saturday, 13 October 2018 at 14:32:33 UTC, welkam wrote: On Saturday, 13 October 2018 at 09:22:16 UTC, Vijay Nayar wrote: [...] import algorithm thats all but then it spits out lib/nim/pure/algorithm.nim(144, 11) Error: interpretation requires too many iterations My mistake. I updated the file and forgot to include the 'import algorithm' directive. The file is now fixed to include it. Download the corrected version or patch your file accordingly. As stated in the file intro **YOU MUST DO THIS** to get it to compile with current Nim (they were supposed to fix this in this version 0.19.0 but didn't). To compile for nim versions <= 0.19.0 do following: 1) in file: ~/nim-0.19.0/compiler/vmdef.nim 2) set variable: MaxLoopIterations* = 1_000_000_000 (1 Billion or >) 3) then rebuild sysem: ./koch boot -d:release If you are using 'choosenim' to install Nim (highly advisable) the full path is: ~/.choosenim/toolchains/nim-0.19.0/compiler/vmdef.nim I'll post performance results from my laptop to give reference times to compare against. Ok, now it builds. I was previously following the build instructions from the Nim website and am not super clear what the "koch" tool does, but following your instructions, the program does build and run. I'll take a stab at making a D version. Interesting results so far. I have a partially converted program here: https://gist.github.com/vnayar/79e2d0a9850833b8859dd9f08997b4d7 The interesting part is that during compilation (with the command "dmd twinprimes_ssoz.d"), the compilation will abort with the message "Killed" and no further information. That's a new one for me, so I'm looking into the cause.
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 15:19:07 UTC, Jabari Zakiya wrote: On Saturday, 13 October 2018 at 14:32:33 UTC, welkam wrote: On Saturday, 13 October 2018 at 09:22:16 UTC, Vijay Nayar wrote: [...] import algorithm thats all but then it spits out lib/nim/pure/algorithm.nim(144, 11) Error: interpretation requires too many iterations My mistake. I updated the file and forgot to include the 'import algorithm' directive. The file is now fixed to include it. Download the corrected version or patch your file accordingly. As stated in the file intro **YOU MUST DO THIS** to get it to compile with current Nim (they were supposed to fix this in this version 0.19.0 but didn't). To compile for nim versions <= 0.19.0 do following: 1) in file: ~/nim-0.19.0/compiler/vmdef.nim 2) set variable: MaxLoopIterations* = 1_000_000_000 (1 Billion or >) 3) then rebuild sysem: ./koch boot -d:release If you are using 'choosenim' to install Nim (highly advisable) the full path is: ~/.choosenim/toolchains/nim-0.19.0/compiler/vmdef.nim I'll post performance results from my laptop to give reference times to compare against. Ok, now it builds. I was previously following the build instructions from the Nim website and am not super clear what the "koch" tool does, but following your instructions, the program does build and run. I'll take a stab at making a D version.
Re: A Friendly Challenge for D
On Saturday, 13 October 2018 at 14:32:33 UTC, welkam wrote: On Saturday, 13 October 2018 at 09:22:16 UTC, Vijay Nayar wrote: I downloaded the reference NIM implementation and got the latest nim compiler, but I received the following error: $ nim c --cc:gcc --d:release --threads:on twinprimes_ssoz.nim twinprimes_ssoz.nim(74, 11) Error: attempting to call undeclared routine: 'sort' For a person not familiar with nim, what's the fastest way to fix that? import algorithm thats all but then it spits out lib/nim/pure/algorithm.nim(144, 11) Error: interpretation requires too many iterations I ran into the same problem as you did, and then followed the instructions from the error. I modified the compiler source and increased the number of maximum iterations from 3_000_000 to 1_000_000_000, rebuilt and installed it, but still ran into the exact same problem. There may be something up with the algorithm itself.
Re: A Friendly Challenge for D
On Friday, 12 October 2018 at 21:08:03 UTC, Jabari Zakiya wrote: On Friday, 12 October 2018 at 20:05:29 UTC, welkam wrote: On Friday, 12 October 2018 at 16:19:59 UTC, Jabari Zakiya wrote: The real point of the challenge is too see what idiomatic code... There is no idiomatic D code. There is only better implementations. D doesnt tell you how to write your code. It gives you many tools and you choose which tools to use. That`s what people like about D. I await your implementation(s)! :-) I downloaded the reference NIM implementation and got the latest nim compiler, but I received the following error: $ nim c --cc:gcc --d:release --threads:on twinprimes_ssoz.nim twinprimes_ssoz.nim(74, 11) Error: attempting to call undeclared routine: 'sort' For a person not familiar with nim, what's the fastest way to fix that?
Re: Interesting Observation from JAXLondon
On Friday, 12 October 2018 at 07:13:33 UTC, Russel Winder wrote: On Thu, 2018-10-11 at 13:00 +, bachmeier via Digitalmars-d wrote: […] Suggestions? My guess is that the reason they've heard of those languages is because their developers were writing small projects using Go and Rust, but not D. I fear it may already be too late. Go, and now Rust, got marketing hype from an organisation putting considerable resources into the projects. This turned into effort from the community that increased rapidly, turning the hype into frameworks and libraries, and word of mouth marketing. It is the libraries and frameworks that make for traction. Now the hype is gone, Go and Rust, and their libraries and frameworks, are well positioned and with significant penetration into the minds of developers. Talk to Java developers and they have heard of Go and Rust, but not D. Go is more likely to them because of Docker and the context of The Web, for which Go has a strong pitch. They have heard of Rust but usually see it as not relevant to them, despite Firefox. Talk to Python developers and they know of Go, many of them of Rust, but almost never D. C and C++ are seen as the languages of performance extensions, though Rust increasingly has a play there. D has vibe.d, PyD, GtkD, and lots of other bits, but they've never quite had the resources of the equivalents in Go and Rust. Also the D community as a whole is effectively introvert, whereas Go and Rust communities have been quite extrovert. "Build it and they will come" just doesn't work, you have to be pushy and market stuff, often using guerilla marketing, to get mindshare. D has an excellent position against Python (for speed of development but without the performance hit) but no chance of penetrating the places where Python is strong due to lack of libraries and frameworks that people use – cf. Pandas, SciKit.Learn, etc. D has an excellent position against Go as a language except that Go has goroutines and channels. The single threaded event loop and callback approach is losing favour. Kotlin is introducing Kotlin Coroutines which is a step on from the observables system of Rx. Structured concurrency abstracting away from fibres and threadpools. Java may well get this via Project Loom which is Quasar being inserted into the JVM directly. Whatever D has it doesn't seem to be going to compete in this space. D without the GC has a sort of position against Rust, but I think that battle has been lost. Rust has won in the "the new C that isn't Go and doesn't have a garbage collector, and isn't C++, but does have all the nice monads stuff, oh and memory safety mostly". When it comes down to it D will carry on as a niche language loved by a few unknown to most. In my opinion, I don't think the game is over just yet. One of D's biggest strengths has been its ability to adapt and innovate. Despite being around since 2001, it is still forging ahead and many of the new features coming out in programming languages are coming to fruition in D before being back-ported to other languages. The D crowd is certainly very introverted and very technically minded, it really seems to be an amazing hub for innovators and compiler designers. But the D community has also been very receptive of changes to the language which allows it to evolve at a pace few other languages can match. My personal opinion is that languages that grow up too fast get stuck because they have too much legacy code and certain options that they may have originally wanted become unavailable. Go and Rust are gaining traction, especially among developers getting tired of very hard to work with languages. Java is very very slow to evolve and there's a huge amount of effort invested in learning other JVM languages like Scala, I think largely because people are looking for alternatives. Rust, while intriguing, is very alien in syntax and concept for many developers. Go gets wider adoption than other languages I've seen, but the race is still on in my book. One thing that does concern me, is the avenues in which people can discover D. For me personally, after a particularly nasty C++ project, I just googled for "alternatives to C++" and that's how I found D back in 2009 or so. But the same search today turns up nothing about D. I'm not sure sure how people are supposed to find D.
Re: Interesting Observation from JAXLondon
On Thursday, 11 October 2018 at 11:50:39 UTC, Joakim wrote: On Thursday, 11 October 2018 at 07:58:39 UTC, Russel Winder wrote: This was supposed to come to this list not the learn list. On Thu, 2018-10-11 at 07:57 +0100, Russel Winder wrote: It seems that in the modern world of Cloud and Kubernetes, and the charging model of the Cloud vendors, that the startup times of JVMs is becoming a financial problem. A number of high profile companies are switching from Java to Go to solve this financial difficulty. It's a pity D is not in there with a pitch. I suspect it is because the companies have heard of Go (and Rust), but not D. I doubt D could make a pitch that would be heard, no google behind it and all that jazz. D is better aimed at startups like Weka who're trying to disrupt the status quo than Java shops trying to sustain it, while shaving off some up-front time. Personally I think this is going to change soon depending on what options are available. The amount of time and money that companies, especially companies using Java and AWS, are putting in to saving money with Nomad or Kubernetics on the promise of having more services per server is quite high. However, these JVM based services run in maybe 1-2GB of RAM at the minimum, so they get maybe 4 services per box. A microservice built using D and vibe.d could easily perform the same work using less CPU and maybe only 500MB of RAM. The scale of improvement is roughly the same as what you would get by moving to containerization. If D has the proper libraries and integrations available with the tools that are commonly used, it could easily break through and become the serious language to use for the competitive business of the future. But libraries and integrations will make or break that. It's not just Java you're up against, it's all the libraries like SpringBoot and all the integrations with AWS systems like SQS, SNS, Kinesis, MySQL, PostGREs, Redis, etc. My hope is that D will be part of that future and I'm trying to add libraries as time permits.
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 `` 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. = 0x7ffd0800acb8, a = 0x7fd6b05b, a.data=4 = 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.data = ", a.data); } f(a); writeln(" = ", , ", a.data = ", a.data); } // Output: = 7FFEA6BA3158, a.data = 4 // Addresses are different, from different class variables. = 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?
Associative Array that Supports upper/lower Ranges
I was in need of an associative array / dictionary object that could also support getting ranges of entries with keys below or above a given value. I couldn't find anything that would do this, and ended up using the RedBlackTree to store key/value pairs, and then wrap the relevant functions with key lookups. I feel that there was probably an easier way to do this, but I didn't find one. Regardless, if anyone else has this kind of problem, you can get around it like this: ``` module rbtree_map; import std.container.rbtree; import std.algorithm : map; import std.functional : binaryFun; import std.meta : allSatisfy; import std.range : ElementType, isInputRange; import std.traits : isDynamicArray, isImplicitlyConvertible; /** * A dictionary or associative array backed by a Red-Black tree. */ unittest { auto rbTreeMap = new RBTreeMap!(string, int)(); rbTreeMap["a"] = 4; rbTreeMap["b"] = 2; rbTreeMap["c"] = 3; rbTreeMap["d"] = 1; rbTreeMap["e"] = 5; assert(rbTreeMap.length() == 5); assert("c" in rbTreeMap); rbTreeMap.removeKey("c"); assert("c" !in rbTreeMap); rbTreeMap.lowerBound("c"); // Range of ("a", 4), ("b", 2) rbTreeMap.upperBound("c"); // Range of ("d", 1), ("e", 5) } final class RBTreeMap(KeyT, ValueT, alias KeyLessF = "a < b", bool allowDuplicates = false) { public: static struct Pair { KeyT key; ValueT value; } alias keyLess = binaryFun!KeyLessF; alias RedBlackTreeT = RedBlackTree!(Pair, (pair1, pair2) => keyLess(pair1.key, pair2.key), allowDuplicates); RedBlackTreeT rbTree; // Forward compatible methods like: empty(), length(), opSlice(), etc. alias rbTree this; this() { rbTree = new RedBlackTreeT(); } this(Pair[] elems...) { rbTree = new RedBlackTreeT(elems); } this(PairRange)(PairRange pairRange) if (isInputRange!PairRange && isImplicitlyConvertible!(ElementType!PairRange, Pair)) { rbTree = new RedBlackTreeT(pairRange); } override bool opEquals(Object rhs) { RBTreeMap that = cast(RBTreeMap) rhs; if (that is null) return false; return rbTree == that.rbTree; } /// Insertion size_t stableInsert(K, V)(K key, V value) if (isImplicitlyConvertible!(K, KeyT) && isImplicitlyConvertible!(V, ValueT)) { return rbTree.stableInsert(Pair(key, value)); } alias insert = stableInsert; ValueT opIndexAssign(ValueT value, KeyT key) { rbTree.stableInsert(Pair(key, value)); return value; } /// Membership bool opBinaryRight(string op)(KeyT key) const if (op == "in") { return Pair(key) in rbTree; } /// Removal size_t removeKey(K...)(K keys) if (allSatisfy!(isImplicitlyConvertibleToKey, K)) { KeyT[K.length] toRemove = [keys]; return removeKey(toRemove[]); } //Helper for removeKey. private template isImplicitlyConvertibleToKey(K) { enum isImplicitlyConvertibleToKey = isImplicitlyConvertible!(K, KeyT); } size_t removeKey(K)(K[] keys) if (isImplicitlyConvertible!(K, KeyT)) { auto keyPairs = keys.map!(key => Pair(key)); return rbTree.removeKey(keyPairs); } size_t removeKey(KeyRange)(KeyRange keyRange) if (isInputRange!KeyRange && isImplicitlyConvertible!(ElementType!KeyRange, KeyT) && !isDynamicArray!KeyRange) { auto keyPairs = keys.map(key => Pair(key)); return rbTree.removeKey(keyPairs); } /// Ranges RedBlackTreeT.Range upperBound(KeyT key) { return rbTree.upperBound(Pair(key)); } RedBlackTreeT.ConstRange upperBound(KeyT key) const { return rbTree.upperBound(Pair(key)); } RedBlackTreeT.ImmutableRange upperBound(KeyT key) immutable { return rbTree.upperBound(Pair(key)); } RedBlackTreeT.Range lowerBound(KeyT key) { return rbTree.lowerBound(Pair(key)); } RedBlackTreeT.ConstRange lowerBound(KeyT key) const { return rbTree.lowerBound(Pair(key)); } RedBlackTreeT.ImmutableRange lowerBound(KeyT key) immutable { return rbTree.lowerBound(Pair(key)); } auto equalRange(KeyT key) { return rbTree.equalRange(Pair(key)); } } ```
Re: Expanding tool (written in D) use, want advice
On Friday, 22 June 2018 at 14:45:46 UTC, Jesse Phillips wrote: Should I be looking more at the benefits of having D as a tool? It was a good choice for me since I know D so well (and other reasons at the time), but C# is a reasonable language in this space. I'm thinking, like should I go into how learning D wouldn't be too hard for new hire since it has similar syntax to C# and so on. One strong argument to make is based on performance. Give them numbers about how fast your tool runs and make it efficient. The idea is that because the linting tool will be run for every incremental build a developer makes, slower running times are a barrier to productivity. But once performance targets are defined, and if the company thinks that C# can also meet those targets, then really it's their call. Ultimately it is their company and their assets. In such a case, I would generalize your tool for use outside of the specific context of your company, and make it the basis of an open source project.
Re: detectcycles: A source code dependency cycle checker
On Sunday, 17 June 2018 at 20:20:48 UTC, Mario Kröplin wrote: I did not mention it in the README, but the tred filter used in https://code.dlang.org/packages/depend complains about cyclic dependencies. I am currently working on a branch, where the transitive reduction and the corresponding warnings are built in. While this tool is for D only, it also allows to visualize and to check dependencies. Very nice project. The PlantUML output is a brilliant idea. In my case, I am mostly analyzing projects that are NOT in D, so I need a general purpose tool. I'm putting it through practical runs this morning and discovering areas of improvement. For example, in Java, one need not import dependencies within the same package, so I need to take a list of "uses" regex patterns instead of just having a single one, so that things like "@Autowired" from Spring can be detected as well.
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?
detectcycles: A source code dependency cycle checker
https://github.com/vnayar/detectcycles I made a small configurable tool to detect software source dependency cycles that is configurable to use for most languages. By default, C++, Java, and D are supported, but add new languages is as simple as adding a few lines to JSON configuation file. I often work on very large software projects in various different languages, and sometimes you walk onto projects that were large long before you got there. Part of my work involves re-architecting and breaking apart monolithic code bases, and knowing which components have been tied together as a block is useful for a quick analysis and helps show me where I need to focus my attention. Hopefully other people find it useful as well.
Re: What's happening with the `in` storage class
On Saturday, 9 June 2018 at 02:38:14 UTC, SonicFreak94 wrote: On Saturday, 9 June 2018 at 02:17:18 UTC, Adam D. Ruppe wrote: On Saturday, 9 June 2018 at 02:13:00 UTC, Walter Bright wrote: But it was never enforced, meaning that suddenly enforcing it is just going to break code left and right. It isn't going to break anything. It is going to *correctly diagnose already broken code*. That's a significant difference. Real world D users don't like broken code, but they DO like the compiler catching new bugs that slipped by before. I agree. I would rather my potentially broken code be pointed out to me rather than removing the much more concise `in` from my code. In any case, I feel as though the concept of both `in` and `out` should be fairly intuitive. `in` would be a read-only reference (C# has received this recently), and `out` is a reference with the intention to write. 100% agreed. I always found "in" to be consistent with what I view as one of D's core philosophies, that the simple thing should be the right thing. For example, when you have a class parameter, it is automatically passed by reference without any other special considerations by the programmer. To me, "in" has been a shorthand to communicate my desire to make sure that the parameter is treated strictly as an input, and not modified in any way or having ways to pass its reference to others who may then modify it. Where I may be doing something wrong, a helpful message from the compiler is welcome.
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 19:17:37 UTC, Vijay Nayar wrote: On Tuesday, 29 May 2018 at 12:58:20 UTC, Yuxuan Shui wrote: [...] I tried this again, this time completely ignoring lambdas and completely specifying the desired type like so: [...] Issue created: https://issues.dlang.org/show_bug.cgi?id=18917
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 12:58:20 UTC, Yuxuan Shui wrote: I believe that is the case. Normally that will be fine, because you can't modify them. Type-deduced lambda is a very special case, as in their parameter types are deduced on first use, so in a sense, they are "modified" by the first instantiation. BTW, I can't find the documentation about defining lambda with their parameter types omitted anywhere. I tried this again, this time completely ignoring lambdas and completely specifying the desired type like so: final class BTree( ValueT, KeyT = ValueT, const(KeyT) function(ValueT) nothrow pure @nogc KeyF = function KeyT(ValueT a) { return a; }) { KeyT getKey(ValueT val) { return KeyF(val); } } But unfortunately, the following code still produces an error: void main() { auto btree1 = new BTree!(char); auto btree2 = new BTree!(int); // The error is on this line. } onlineapp.d(17): Error: template instance `BTree!int` does not match template declaration `BTree(ValueT, KeyT = ValueT, const(char) function(char) pure nothrow @nogc KeyF = function KeyT(ValueT a) { return a; } )` I think at this point this may be a bug in the compiler. What do you think?
Re: Clash When Using Function as Template Value-Parameters?
On Tuesday, 29 May 2018 at 11:36:11 UTC, Yuxuan Shui wrote: No, wait a second. (a)=>a is in default argument list, so it is in the global scope. And it was instantiated when you instantiate BTree with char. Could you explain that part a bit for me? Yes, (a) => a is a default value, but when you say it is in the global scope, are you saying that a single object "(a) => a" is created in the global scope and not created for each template argument list, e.g. "BTree!int" and "BTree!char"? I actually do not know in what scope such objects would be created, I had assumed it was per template-parameter list, but are you saying this is not the case?
Re: Clash When Using Function as Template Value-Parameters?
On Sunday, 27 May 2018 at 20:38:25 UTC, Daniel Kozak wrote: I would rewrite it to something like this: template BTree(ValueT, KeyT = ValueT,alias KeyF = unaryFun!"cast(const)a") { class BTree { This is roughly what I originally had, but it creates a number of problems that I wanted to get around. Changing KeyF back to an alias means that any function that uses it can no longer be const, pure, @nogc, or nothrow. Essentially the parameter is just anything the user provides. If I use a template value-parameter, then it forces any lambda the user passes in to either match the type I enter in (with const, pure, etc.) or the program to fail to compile. That is, I don't want the user to pass in any function, but only functions with the desired attributes. I.e., I wouldn't want them to pass in for KeyF something like "a.data--". Listing out the full type does indeed work correctly with various examples, and letting the user pass in something like `a => a._id` does compile, but the only problem is that when there are two such template instances in the same program. Logically `BTree!(MyStruct, int, a => a.id)`, `BTree!(AnotherStruct, char, a => a.name[0])`, `BTree!int` and `BTree!char` should all be totally independent. But for reasons unknown, the individual parameters seems to be swapped and and confused during compilation. In the error above I listed. The function parameter from `BTree!char` is being used to create a compile error against `BTree!int`, which is very odd. Each of these classes compile and run just fine individually, the compilation only breaks when both exist.
Re: Friends in D, a new idiom?
On Sunday, 27 May 2018 at 06:37:56 UTC, IntegratedDimensions wrote: I'm looking for something lightweight and direct. It is not for total encapsulation control but to simply provide an extra level of indirection for write access to make the object look read only to those that directly use it. I think const is something that may be helpful then. If applied consistently, especially with methods, it can also protect you from accidentally making mutations in functions where were originally intended to be read-only. Having an object "look" read-only is more of a stylistic thing based on conventions about method naming, etc. Personally I lean towards having the compiler enforce it.
Re: Clash When Using Function as Template Value-Parameters?
On Saturday, 26 May 2018 at 11:56:30 UTC, Vijay Nayar wrote: The error is: ``` onlineapp.d(8): Error: function literal `__lambda6(char a)` is not callable using argument types `(int)` onlineapp.d(8):cannot pass argument `val` of type `int` to parameter `char a` onlineapp.d(15): Error: template instance `onlineapp.BTree!(int, int, function (char a) => a)` error instantiating ``` Just to clarify. In the example above, if I create a 'BTree!int' by itself, it's fine. If I create a 'BTree!char' by itself, it's fine also. But if I create both, even if they are created in different modules, the compiler seems to mix up the types of the function template-parameter, and tries to fit a 'char' to the 'int' function or an 'int' to the 'char' function, depending on which was declared first.
Re: General problem I'm having in D with the type system
On Sunday, 27 May 2018 at 06:00:30 UTC, IntegratedDimensions wrote: The problem description is not very clear, but the catfood example gives a bit more to work with. animal -> food || vv cat -> catfood Of course, I'm not sure how to avoid the problem in D of animal a = new cat(); a.f = new food() auto c = cast(cat)a; Cast operations are generally not guaranteed to preserve type safety and should be avoided when possible. But if I understand your description, you have the following relations and transitions: animal owns food catowns catfood animal may be treated as a cat (hence the casting) food may be treated as a catfood (hence the casting) It may be that the inheritance relationship is backwards in your use case. If "animal" may be treated as a "cat", then the inheritance should be other other way around, and "animal" would inherit from "cat". What specific kinds of relationships are you trying to model among what kinds of entities?
Re: Friends in D, a new idiom?
On Sunday, 27 May 2018 at 05:25:53 UTC, IntegratedDimensions wrote: Re: Friends in D, a new idiom? In D, there's no exact equivalent to friend, but there are a few more specialized tools at your disposal. Normally all code in the same module is essentially a friend, so if the classes you are dealing with are tightly coupled, they can simply be in the same module. For example: module m; class C { // This is still visible in the same module. // See https://dlang.org/spec/attribute.html#VisibilityAttribute private int data; ... } class CAccessor { C _this; this(C c) { _this = c; } @property void data(int v) { _this.data = v; } ... } Initially I thought nested classes contained an inherent super but I guess that is not the case? Super is for inheritance rather than inner classes. So another way to tackle your problem using super would be this: class C { protected int _data; @property int data() { return _data; } } class CAccessor : C { @property void data(int v) { _data = v; } C toC() { return this; } } I also imagine that one could enhance this so that write access could also be allowed by certain types. The 'package' visibility attribute can also be given a parameter if you need to limit access only to certain module. Any ideas about this type of pattern, how to make it better, already exists etc? You might be looking for the "Builder Pattern" which uses a separate object to construct and modify objects, and then it creates a read-only object with those values upon request. Also, I would recommend using "const" to control access as well. Setter methods will not be const, but getters will be. Those that have a `const(C)` reference will only be able to read, and those with a `C` will be able to call all methods. For example: class C { private int _data; @property int data() const { return _data; } @property void data(int v) { _data = v; } } void main() { C a = new C(); const(C) b = a; a.data(3); a.data(); b.data(); // b.data(4); Compile error. }
Clash When Using Function as Template Value-Parameters?
I've been experimenting with code that uses std.functional : binaryFun and unaryFun, but I have found that using these methods makes it impossible to add function attributes like @safe, @nogc, pure, and nothrow, because no guarantee can be made about the functions created via a stream. For example, if you expect a comparator function like "a == b", someone can pass in "a.data--" instead. That being said, I started trying out using strongly typed and attributed template parameters instead, relying on lambdas to keep the syntax for the user short. But when I tried this, I found that the very existence of templates with different parameter values causes a collision during compilation. The following code snippet demonstrates the error: ``` import std.stdio; final class BTree( ValueT, KeyT = ValueT, const(KeyT) function(ValueT) @safe @nogc nothrow pure KeyF = (a) => a) { KeyT getKey(ValueT val) { return KeyF(val); } } void main() { auto btree1 = new BTree!(char); // Removing this line eliminates the error. auto btree2 = new BTree!(int); } ``` The error is: ``` onlineapp.d(8): Error: function literal `__lambda6(char a)` is not callable using argument types `(int)` onlineapp.d(8):cannot pass argument `val` of type `int` to parameter `char a` onlineapp.d(15): Error: template instance `onlineapp.BTree!(int, int, function (char a) => a)` error instantiating ``` Is this an error in the compiler or in my own understanding of the D language?
Bug?: Presence of "init()" Method Causes std.array.appender to Fail to Compile
I encountered a very unexpected error when working on a project. It seems that the Appender and RefAppender structs created from the std.array.appender() method are sensitive to the mere presence of a method called "init()" on the element type of the array. Here is a minimal example: ``` import std.array; struct S1 { // The mere presence of this method causes the error, deleting it fixes the error. void init(string p1, int p2, int p3) { } } struct S2 { S1[] a; RefAppender!(int[]) getAppender() { return appender(); } } void main() { } ``` The compiler produces the following output: ``` /dlang/dmd/linux/bin64/../../src/phobos/std/array.d(2907): Error: cannot have array of `void(string, int, int)` /dlang/dmd/linux/bin64/../../src/phobos/std/array.d(2976): Error: cannot have array of `inout void(string, int, int)` /dlang/dmd/linux/bin64/../../src/phobos/std/array.d(3369): Error: template instance `std.array.Appender!(S1[])` error instantiating /dlang/dmd/linux/bin64/../../src/phobos/std/array.d(3879): instantiated from here: `RefAppender!(S1[])` onlineapp.d(12):instantiated from here: `appender!(S1[]*, S1)` /dlang/dmd/linux/bin64/../../src/phobos/std/array.d(3429): Error: cannot have array of `inout void(string, int, int)` ``` Is this a bug or a misunderstanding on my part?
Should 'in' Imply 'ref' as Well for Value Types?
While working on a library built for high efficiency, avoiding unnecessary copies of structs became an issue. I had assumed that `in` was doing this, but a bit of experimentation revealed that it does not. However, `ref in` works great. My question is, should `in` by default also imply `ref` for value types like structs? Is there a reason not to do this? This is the test program I used for reference: ``` import std.stdio; struct Bob { int a; this(this) { writeln(""); } } void main() { Bob b = Bob(3); writeln(" = ", ); void showAddrIn(in Bob b) { writeln("(showAddrIn) = ", ); } showAddrIn(b); void showAddrRefIn(ref in Bob b) { writeln("(showAddrRefIn) = ", ); } showAddrRefIn(b); } ``` The output is as follows: ``` = 7FFD9F526AD0 (showAddrIn) = 7FFD9F526AB0 (showAddrRefIn) = 7FFD9F526AD0 ```
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?