Re: Compile-time variables
On Friday, 6 April 2018 at 02:18:28 UTC, Kayomn wrote: On Friday, 6 April 2018 at 01:22:42 UTC, Kayomn wrote: On Friday, 6 April 2018 at 01:14:37 UTC, ketmar wrote: Kayomn wrote: [...] it is already done for you, free of charge. class Node {} class RootNode : Node {} class SpriteNode : Node {} void main () { auto nodeId1 = typeid(Node); auto nodeId2 = typeid(SpriteNode); auto comparison = typeid(Node); Node n = new SpriteNode(); assert(typeid(Node) is typeid(Node)); // obviously assert(typeid(SpriteNode) !is typeid(Node)); // sure assert(typeid(Node) is nodeId1); assert(typeid(n) is nodeId2); } Oh neat, thanks. I've been really scraping my head over this, and was worried I wouldn't be able to keep supporting my D version of the project. Hmm... doesn't seem to operate at compile-time, which is an issue if I want to use it in case switch table like I was going to: switch (queryInteger(childJson,"type")) { case NodeType.Sprite: child = this.addChild!(Sprite)(childName); break; default: child = this.addChild!(Node)(childName); break; } Wrong example code, here's the correct example: switch (queryString(childJson,"type")) { case (typeof (Sprite).name): child = this.addChild!(Sprite)(childName); break; case (typeof (Camera).name): child = this.addChild!(Camera)(childName); break; default: child = this.addChild!(Node)(childName); break; }
Re: Compile-time variables
On Friday, 6 April 2018 at 01:22:42 UTC, Kayomn wrote: On Friday, 6 April 2018 at 01:14:37 UTC, ketmar wrote: Kayomn wrote: [...] it is already done for you, free of charge. class Node {} class RootNode : Node {} class SpriteNode : Node {} void main () { auto nodeId1 = typeid(Node); auto nodeId2 = typeid(SpriteNode); auto comparison = typeid(Node); Node n = new SpriteNode(); assert(typeid(Node) is typeid(Node)); // obviously assert(typeid(SpriteNode) !is typeid(Node)); // sure assert(typeid(Node) is nodeId1); assert(typeid(n) is nodeId2); } Oh neat, thanks. I've been really scraping my head over this, and was worried I wouldn't be able to keep supporting my D version of the project. Hmm... doesn't seem to operate at compile-time, which is an issue if I want to use it in case switch table like I was going to: switch (queryInteger(childJson,"type")) { case NodeType.Sprite: child = this.addChild!(Sprite)(childName); break; default: child = this.addChild!(Node)(childName); break; }
Re: Game and GC
On Friday, 23 February 2018 at 03:25:33 UTC, Norm wrote: On Friday, 23 February 2018 at 01:54:07 UTC, Leonardo wrote: Hi, I'm new to language and games. Many people say that GC is bad and can slow down your project in some moments. What can happen if I create a game using D without worrying with memory management? (using full GC) Have a look at https://github.com/gecko0307/atrium and see how memory is handled there. TBH though every game I've written I have not worried about the GC and just code it up. This works fine for 2d games, platformers etc. If it ever does bite you can always schedule the pauses (they are deterministic in the sense a collect will occur on allocation) or do pretty much what every game does in C++/C and allocate in pools. Cheers, Norm Atrium game use Dlib, more specific this module to manually manage memory. Appears to be very easy to use. Thanks. https://github.com/gecko0307/dlib/wiki/dlib.core.memory
Re: Compile-time variables
On Friday, 6 April 2018 at 01:14:37 UTC, ketmar wrote: Kayomn wrote: [...] it is already done for you, free of charge. class Node {} class RootNode : Node {} class SpriteNode : Node {} void main () { auto nodeId1 = typeid(Node); auto nodeId2 = typeid(SpriteNode); auto comparison = typeid(Node); Node n = new SpriteNode(); assert(typeid(Node) is typeid(Node)); // obviously assert(typeid(SpriteNode) !is typeid(Node)); // sure assert(typeid(Node) is nodeId1); assert(typeid(n) is nodeId2); } Oh neat, thanks. I've been really scraping my head over this, and was worried I wouldn't be able to keep supporting my D version of the project.
Re: Compile-time variables
On Friday, April 06, 2018 00:35:39 Kayomn via Digitalmars-d-learn wrote: > On Friday, 6 April 2018 at 00:21:54 UTC, H. S. Teoh wrote: > > On Thu, Apr 05, 2018 at 11:53:00PM +, Kayomn via > > Digitalmars-d-learn wrote: [...] > > > >> [...] > > > > [...] > > > >> [...] > > > > `lastID`, as declared above, are runtime variables. The > > 'static' in this case just means it's thread-local, rather than > > allocated on the stack. You cannot modify these variables at > > compile-time. > > > >> [...] > > > > You appear to be wanting to increment a global variable during > > compile-time. Unfortunately, there is no such thing as a > > compile-time global variable. You will have to find some other > > way to implement what you want. > > > > One way to do this would be to use compile-time introspection > > to construct a list of nodes, and then use a CTFE function or > > > > static foreach to generate node IDs all at once. For example: > > string generateEnum(T...)() > > { > > > > if (__ctfe) { // only run at compile-time > > > > string code = "enum NodeIds {"; > > foreach (ident; T) { > > > > code ~= ident ~ ", "; > > > > } > > code ~= "}"; > > return code; > > > > } > > else assert(0); > > > > } > > > > alias MyNodes = List!( > > > > // Just an example; you probably want to generate this > > // list via introspection, e.g. via __traits(getMembers) > > // or something like that. > > identifier1, > > identifier2, > > ... > > > > ); > > > > mixin(generateEnum!MyNodes); // defines `enum NodeIds` > > > > static assert(NodeIds.identifier1 == 0); > > static assert(NodeIds.identifier2 == 1); > > ... > > > > There are probably other ways to do it too, but I chose enum > > because it naturally assigns incrementing IDs to its members, > > so it's a convenient construct for this purpose. > > > > > > T > > I think I didn't explain well enough, I'm not trying to generate > an enum from a list of pre-defined known quantities. The idea is > that a compile-time generic function exists and it generates a > unique identifier for that node. > > My reasons for doing this is to remove the need to keep a master > enum that holds an identifying value for each node. I've > implemented this same thing in C++ before and it was extremely > straightforward. If you want to generate a value using CTFE, then you can use a normal function that simply takes arguments and returns a value, and you can use enums that already have a value. So, you can do something like enum foo = "string"; enum bar = baz("2"); string baz(string str) { return foo ~ str; } void main() { assert(foo == "string"); assert(bar == "string2"); } but you can't use any variables other than local variables unless they're const or immutable. So, you can't do something like increment a global variable. It's is absolutely impossible to do something like enum id = getID(); and have getID return a different value on each call. So, if you're looking to do something like enum value1 = getID(); enum value2 = getID(); enum value3 = getID(); enum value4 = getID(); and have each of those enums have a unique ID, then you are completely out of luck. You'll need go about solving the problem in a different way, be it by passing different values to the function being used so that it can generate different values on each call: enum value1 = getID(1); enum value2 = getID(2); enum value3 = getID(3); enum value4 = getID(4); or by generating a string to mix in as code as H. S. Teoh suggested. Eponymous templates or template mixins could also be used, but they don't really do anything more, just differently, and usually less efficiently. Basically, even though functions used during CTFE don't have to be marked with pure, they effectively have to be pure in order to work. So, if you try to initialize an enum with the result of a function call, the only way you have to alter the output is to pass in different arguments. If you need any kind of state to be maintained in order to initialize multiple enums with values that relate to one another (e.g. an incrementing ID), then a mixin is your only choice. If you can initialize what you need to initialize at runtime (meaning that it can't be an enum), then you have more options, but at compile time, initializations have to be pure. - Jonathan M Davis
Re: Compile-time variables
Kayomn wrote: I'll give a better example of what it is I'm trying to do. These are node types. Their contents are not important in this explanation, only that they operate as a tree structure. class Node; class RootNode : Node; class SpriteNode : Node; The result of getNodeID on a specific type is always the same. A value representing it that is applied during compilation. The value does not matter to the programmer, only that it is unique and gets applied. -- uint nodeId1 = getNodeID!(Node)(); // 0. uint nodeId2 = getNodeID!(SpriteNode)(); // 1. uint comparison = getNodeID!(Node)(); // 0. // True. if (getNodeID!(Node)() == getNodeID!(Node)()) { } // False. if (getNodeID!(SpriteNode)() == getNodeID!(Node)()) { } -- it is already done for you, free of charge. class Node {} class RootNode : Node {} class SpriteNode : Node {} void main () { auto nodeId1 = typeid(Node); auto nodeId2 = typeid(SpriteNode); auto comparison = typeid(Node); Node n = new SpriteNode(); assert(typeid(Node) is typeid(Node)); // obviously assert(typeid(SpriteNode) !is typeid(Node)); // sure assert(typeid(Node) is nodeId1); assert(typeid(n) is nodeId2); }
Re: Compile-time variables
I'll give a better example of what it is I'm trying to do. These are node types. Their contents are not important in this explanation, only that they operate as a tree structure. class Node; class RootNode : Node; class SpriteNode : Node; The result of getNodeID on a specific type is always the same. A value representing it that is applied during compilation. The value does not matter to the programmer, only that it is unique and gets applied. -- uint nodeId1 = getNodeID!(Node)(); // 0. uint nodeId2 = getNodeID!(SpriteNode)(); // 1. uint comparison = getNodeID!(Node)(); // 0. // True. if (getNodeID!(Node)() == getNodeID!(Node)()) { } // False. if (getNodeID!(SpriteNode)() == getNodeID!(Node)()) { } --
Re: Compile-time variables
On Friday, 6 April 2018 at 00:21:54 UTC, H. S. Teoh wrote: On Thu, Apr 05, 2018 at 11:53:00PM +, Kayomn via Digitalmars-d-learn wrote: [...] [...] [...] [...] `lastID`, as declared above, are runtime variables. The 'static' in this case just means it's thread-local, rather than allocated on the stack. You cannot modify these variables at compile-time. [...] You appear to be wanting to increment a global variable during compile-time. Unfortunately, there is no such thing as a compile-time global variable. You will have to find some other way to implement what you want. One way to do this would be to use compile-time introspection to construct a list of nodes, and then use a CTFE function or static foreach to generate node IDs all at once. For example: string generateEnum(T...)() { if (__ctfe) { // only run at compile-time string code = "enum NodeIds {"; foreach (ident; T) { code ~= ident ~ ", "; } code ~= "}"; return code; } else assert(0); } alias MyNodes = List!( // Just an example; you probably want to generate this // list via introspection, e.g. via __traits(getMembers) // or something like that. identifier1, identifier2, ... ); mixin(generateEnum!MyNodes); // defines `enum NodeIds` static assert(NodeIds.identifier1 == 0); static assert(NodeIds.identifier2 == 1); ... There are probably other ways to do it too, but I chose enum because it naturally assigns incrementing IDs to its members, so it's a convenient construct for this purpose. T I think I didn't explain well enough, I'm not trying to generate an enum from a list of pre-defined known quantities. The idea is that a compile-time generic function exists and it generates a unique identifier for that node. My reasons for doing this is to remove the need to keep a master enum that holds an identifying value for each node. I've implemented this same thing in C++ before and it was extremely straightforward.
Re: Compile-time variables
On Thu, Apr 05, 2018 at 11:53:00PM +, Kayomn via Digitalmars-d-learn wrote: [...] > --- > alias NodeTypeID = uint; > > enum NodeTypeID getNodeID() { > static NodeTypeID lastID = 0; > > return lastID++; > } > > enum NodeTypeID getNodeID(T)() { > static NodeTypeID typeID = getNodeID(); > > return typeID; > } > --- > > The expectation is that this is executed at compile time, [...] > However, I've been struggling with an error pertaining to getNodeType. > The return statement of lastID++ is flagging the error "Static > variable cannot be read at compile time." `lastID`, as declared above, are runtime variables. The 'static' in this case just means it's thread-local, rather than allocated on the stack. You cannot modify these variables at compile-time. > I may just be taking too much of a C++ lens to this, but to me this > seems like it should work? Am I missing a qualifier or something here? You appear to be wanting to increment a global variable during compile-time. Unfortunately, there is no such thing as a compile-time global variable. You will have to find some other way to implement what you want. One way to do this would be to use compile-time introspection to construct a list of nodes, and then use a CTFE function or static foreach to generate node IDs all at once. For example: string generateEnum(T...)() { if (__ctfe) { // only run at compile-time string code = "enum NodeIds {"; foreach (ident; T) { code ~= ident ~ ", "; } code ~= "}"; return code; } else assert(0); } alias MyNodes = List!( // Just an example; you probably want to generate this // list via introspection, e.g. via __traits(getMembers) // or something like that. identifier1, identifier2, ... ); mixin(generateEnum!MyNodes); // defines `enum NodeIds` static assert(NodeIds.identifier1 == 0); static assert(NodeIds.identifier2 == 1); ... There are probably other ways to do it too, but I chose enum because it naturally assigns incrementing IDs to its members, so it's a convenient construct for this purpose. T -- Having a smoking section in a restaurant is like having a peeing section in a swimming pool. -- Edward Burr
Compile-time variables
Hi, I've got a scene graph which contains multiple inheriting types. As such, I've been tagging them with a type enum for whenever I need to do things such as loading a structure from binary. Up until now I've been using an enum that looks like this: --- enum NodeType : uint { None, Root, Sprite, Camera } --- I'm trying to implement a dynamic type ID assignment system that utilizes D generics to generate an incremental, unique identifier for each node without needing to continuously update a master list. This is what I have so far: --- alias NodeTypeID = uint; enum NodeTypeID getNodeID() { static NodeTypeID lastID = 0; return lastID++; } enum NodeTypeID getNodeID(T)() { static NodeTypeID typeID = getNodeID(); return typeID; } --- The expectation is that this is executed at compile time, generating a specific function for the given generic parameter each time the generic is used, incrementing the static variable by 1 and having the compiled generic functions essentially contain magic number unique to its type. So, I would be able to employ this like so: --- switch (someNodeTypeID) { case getNodeID!(Sprite)(): // Sprite node-specific behavior. break; case getNodeID!(Camera)(): // Camera node-specific behavior. break; default: // Default behavior. break; } --- However, I've been struggling with an error pertaining to getNodeType. The return statement of lastID++ is flagging the error "Static variable cannot be read at compile time." I may just be taking too much of a C++ lens to this, but to me this seems like it should work? Am I missing a qualifier or something here?
Re: Construct immutable member in derived class
On Thursday, 5 April 2018 at 19:31:39 UTC, Jonathan M Davis wrote: And you can't abstract whether a member variable is marked with immutable or not. That's part of the variable. Declaring an immutable instance of an object would then treat the member variable in immutable for that instance, so it's possible to have an immutable member variable when the member variable is not itself marked with immutable, but class inheritance has nothing to do with controlling which type qualifiers were used on the member variable of a base class. Derived classes override member functions. They don't override member variables or anything about them. They override the behavior of the base class, not the structure. That beats my argumentation. Fully agree with that. For them to do otherwise would become quite problematic if you ever use a derived class through a base class reference. They can add onto the structure of a base class, but the derived class must be usuable via a base class reference, and trying to do something like have the derived class alter the qualifiers on base class member variable simply would not work with that. That sort of thing could only ever work if the base class were just a way to add functionality to a derived class rather than having anything to do with references, and that's simply not how classes work in D. If that's the sort of thing that you want, it would make more sense to add the functionality via composition rather than inheritance. Yeah... little bit of mixing things up in my head, maybe... Did exactly this stuff during the last couple of months. Thanks a lot!
Re: Issues using the in-line assembler
Seems I found a better solution hidden in the docs: @nogc protected int[2] transformFunc(int[2] xy){ version(X86){ asm @nogc{ naked; mov EBX, this; movdXMM1, sX[EBX]; pslldq XMM1, 4; movss XMM1, sY[EBX]; movqXMM0, xy; paddd XMM0, XMM1; // [x,y] + [sX,sY] movqXMM3, xy0[EBX]; psubd XMM0, XMM3; // ([x,y] + [sX,sY] - [x_0,y_0]) movqXMM1, ac[EBX]; movqXMM2, bd[EBX]; pmuludq XMM1, XMM0; // [A,0,C,0] * ([x,y] + [sX,sY] - [x_0,y_0]) psrlq XMM1, 16; // ([A,0,C,0] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 movups XMM4, XMM0; psrldq XMM4, 4; pslldq XMM0, 4; por XMM4, XMM0; pmuludq XMM2, XMM4; // [0,B,0,D] * ([x,y] + [sX,sY] - [x_0,y_0]) psrlq XMM2, 16; // ([0,B,0,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 paddq XMM1, XMM2; // ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 punpckldq XMM3, XMM7; paddq XMM1, XMM3; // ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 + [x_0,y_0] movups XMM0, XMM1; // Convert 64 bit vectors into 32 bit ones psrldq XMM0, 4; por XMM0, XMM1; ret ; } }(...) }
Re: Issues using the in-line assembler
On Thursday, 5 April 2018 at 04:48:02 UTC, Basile B. wrote: The "this" seems to be in R11, so you have to apply the asm syntax for accessing the members using .offsetof.[R11], example: ``` class Foo { double a = 123456; extern(D) double foo() { asm { naked; movqXMM0, Foo.a.offsetof[R11]; ret; } } } void main() { import std.stdio; (new Foo).foo(0,0).writeln; } ``` However i cant find any specification saying that R11 is "this". With a free function just pass the instance as param and replace R11 by the register where the instance is passed. It seems that the compiler lets it through if I change it like this: asm @nogc{ naked; movdXMM1, dword ptr sX[EBP]; pslldq XMM1, 4; movss XMM1, dword ptr sY[EBP]; movqXMM0, xy; paddd XMM0, XMM1; // [x,y] + [sX,sY] movqXMM3, qword ptr xy0[EBP]; psubd XMM0, XMM3; // ([x,y] + [sX,sY] - [x_0,y_0]) movqXMM1, qword ptr ac[EBP]; movqXMM2, qword ptr bd[EBP]; pmuludq XMM1, XMM0; // [A,0,C,0] * ([x,y] + [sX,sY] - [x_0,y_0]) psrlq XMM1, 16; // ([A,0,C,0] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 movups XMM4, XMM0; psrldq XMM4, 4; pslldq XMM0, 4; por XMM4, XMM0; pmuludq XMM2, XMM4; // [0,B,0,D] * ([x,y] + [sX,sY] - [x_0,y_0]) psrlq XMM2, 16; // ([0,B,0,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 paddq XMM1, XMM2; // ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 punpckldq XMM3, XMM7; paddq XMM1, XMM3; // ([A,B,C,D] * ([x,y] + [sX,sY] - [x_0,y_0]))>>16 + [x_0,y_0] movups XMM0, XMM1; // Convert 64 bit vectors into 32 bit ones psrldq XMM0, 4; por XMM0, XMM1; ret ; } I wonder if I can return an int[2] in XMM0. I can do some modifications to either move the result to the stack first, or add an import to core.simd (which needs to be refactored completely) and instead make the return type int4 on SIMD enabled CPUs.
Re: Idiomatic error handling for ranges
On Thursday, 5 April 2018 at 17:36:56 UTC, Seb wrote: On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote: Is there a standard way to handle errors in a chain of range transformations? [...] Are you aware of ifThrown? https://dlang.org/phobos/std_exception.html#ifThrown It's not perfect, but imho a nice start and one of the places where lazy really shines. Thanks, ifThrown is perfect.
Re: Construct immutable member in derived class
On Thursday, April 05, 2018 13:36:07 Alex via Digitalmars-d-learn wrote: > On Wednesday, 4 April 2018 at 21:49:08 UTC, Timoses wrote: > > "[...] the construction of the base class can be independent > > from the derived one." > > > > Hm, the points 7 and 8 don't clearly state what you wrote. > > Yes :) > > > But it somehow does make sense.. Still I wonder why that is so. > > > > Let's say you have an abstract class with immutable members. > > Why shouldn't derived class constructors be allowed to > > initialize these immutable members? > > My reason is a semantic one, so it's rather how I'm explaining > this to me, then a formal one. > > Let's assume, we abstract away a member from different derived > classes to an abstract class, which cannot be handled by this > abstract class. > Ok, this can happen, so it would be ok, if the base class does > not handle the var. > > But then, we add a qualifier. How can this be? As the abstract > class cannot handle the abstraction, it also can not add any > qualifiers. > As the qualifier is there, then, the base class at least has > knowledge about the immutability. And due this fact, its own > constructor has to handle this variable in some way. > > However, this a minor problem, isn't it? If you argue, that you > can also abstract the immutability qualifier, then, I would say, > that a derived class always has a better knowledge how to handle > its members, and therefore how to call the base class > constructor, as it knows which class it is derived from. > > So, for short: > Either: the immutability belongs to the base class and therefore > it has to manage the var > Or: it doesn't and the derived classes have the knowledge how to > serve their base class. The reality of the matter is that a member variable is a member of the class that it's in and _must_ be handled by that class. If it's not directly initialized in its declaration or initialized in that class' constructor, then it gets a default value. Derived classes have _zero_ control over that. They can mutate a public or protected mutable member of a base class, but that member variable still has to be initialized by the base class, not the derived class. And you can't abstract whether a member variable is marked with immutable or not. That's part of the variable. Declaring an immutable instance of an object would then treat the member variable in immutable for that instance, so it's possible to have an immutable member variable when the member variable is not itself marked with immutable, but class inheritance has nothing to do with controlling which type qualifiers were used on the member variable of a base class. Derived classes override member functions. They don't override member variables or anything about them. They override the behavior of the base class, not the structure. For them to do otherwise would become quite problematic if you ever use a derived class through a base class reference. They can add onto the structure of a base class, but the derived class must be usuable via a base class reference, and trying to do something like have the derived class alter the qualifiers on base class member variable simply would not work with that. That sort of thing could only ever work if the base class were just a way to add functionality to a derived class rather than having anything to do with references, and that's simply not how classes work in D. If that's the sort of thing that you want, it would make more sense to add the functionality via composition rather than inheritance. - Jonathan M Davis
Re: [OT] Re: merkle reverse
On Thursday, 5 April 2018 at 14:58:21 UTC, Andy Smith wrote: On Thursday, 5 April 2018 at 08:12:38 UTC, aerto wrote: This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4 Yeah. Angela did some messing around with Shadow Volume algorithms before she got into politics... :-) Cheers, A. Is not merkel is merkle, :P
Re: Construct immutable member in derived class
On Wednesday, 4 April 2018 at 22:47:07 UTC, Jonathan M Davis wrote: Because doing that basically makes it impossible to guarantee that the type system isn't violated. Once an immutable variable has been initialized, its value must _never_ change. It must be initalized exactly once, and the compiler doesn't necessarily have any clue what the base class constructors did or didn't do. There's no guarantee that it even has access to the function bodies for the base class when compiling the derived class. So, there is no way for it to safely put off the initialization of any base class members for the derived class to do. - Jonathan M Davis Ah, makes sense. I was looking for a somewhat technical answer. Thanks for that : ).
Re: Idiomatic error handling for ranges
On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote: Is there a standard way to handle errors in a chain of range transformations? [...] Are you aware of ifThrown? https://dlang.org/phobos/std_exception.html#ifThrown It's not perfect, but imho a nice start and one of the places where lazy really shines.
Re: Idiomatic error handling for ranges
On Thursday, 5 April 2018 at 17:06:04 UTC, rumbu wrote: Is there a standard way to handle errors in a chain of range transformations? Let's say I want to read some comma separated numbers from a file. auto myArray = file.byLine().splitter().map!(to!int).array(); Now, besides fatal errors (like I/O), let's suppose I want to handle some errors in a silent way: - skip unicode decoding errors; - assume blank records with 0; - skip the line entirely if the conversion to int is not possible; I can catch UTFException, ConvException or ConvOverflowException for the entire syntax chain but there are some disadvantages: - I don't know exactly which of the chain members thrown the exception; - I cannot skip/handle the error and continue; The only solution I thought about is to break the nice chain syntax and handle errors on each of the chain members, but I wonder if there is probably another way. Thanks. You could use predicates: ``` string list = "3, 5, 1, , not a number, 100"; int[] numbers = list.split(",").filter!((entry) { if (!isNumeric(entry.strip)) return false; else // ... even more cases? return true; }) .map!((e) => e.strip.to!int).array; assert(numbers == [3, 5, 1, 100]); ``` https://run.dlang.io/gist/413282d9726dbac137bf5f35033a8eea
Idiomatic error handling for ranges
Is there a standard way to handle errors in a chain of range transformations? Let's say I want to read some comma separated numbers from a file. auto myArray = file.byLine().splitter().map!(to!int).array(); Now, besides fatal errors (like I/O), let's suppose I want to handle some errors in a silent way: - skip unicode decoding errors; - assume blank records with 0; - skip the line entirely if the conversion to int is not possible; I can catch UTFException, ConvException or ConvOverflowException for the entire syntax chain but there are some disadvantages: - I don't know exactly which of the chain members thrown the exception; - I cannot skip/handle the error and continue; The only solution I thought about is to break the nice chain syntax and handle errors on each of the chain members, but I wonder if there is probably another way. Thanks.
[OT] Re: merkle reverse
On Thursday, 5 April 2018 at 08:12:38 UTC, aerto wrote: This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4 Yeah. Angela did some messing around with Shadow Volume algorithms before she got into politics... :-) Cheers, A.
Re: merkle reverse
On Thursday, 5 April 2018 at 09:49:58 UTC, Seb wrote: Strings are bi-directional ranges, but they aren't random-access nor have a length chunks requires hasSlicing + hasLength: Okay, thanks for the great references. chunks/slide certainly need the length to decide which, and how many, elements to serve in the final chunk. The crucial part is now that an autodecoded string's final element can be determined in O(1) by looking at up to 4 code units from its un-decoded end, whereas its autodecoded length cannot be found in O(1). -- Simon
Re: Construct immutable member in derived class
On Wednesday, 4 April 2018 at 21:49:08 UTC, Timoses wrote: "[...] the construction of the base class can be independent from the derived one." Hm, the points 7 and 8 don't clearly state what you wrote. Yes :) But it somehow does make sense.. Still I wonder why that is so. Let's say you have an abstract class with immutable members. Why shouldn't derived class constructors be allowed to initialize these immutable members? My reason is a semantic one, so it's rather how I'm explaining this to me, then a formal one. Let's assume, we abstract away a member from different derived classes to an abstract class, which cannot be handled by this abstract class. Ok, this can happen, so it would be ok, if the base class does not handle the var. But then, we add a qualifier. How can this be? As the abstract class cannot handle the abstraction, it also can not add any qualifiers. As the qualifier is there, then, the base class at least has knowledge about the immutability. And due this fact, its own constructor has to handle this variable in some way. However, this a minor problem, isn't it? If you argue, that you can also abstract the immutability qualifier, then, I would say, that a derived class always has a better knowledge how to handle its members, and therefore how to call the base class constructor, as it knows which class it is derived from. So, for short: Either: the immutability belongs to the base class and therefore it has to manage the var Or: it doesn't and the derived classes have the knowledge how to serve their base class.
Re: merkle reverse
On Thursday, 5 April 2018 at 09:24:31 UTC, SimonN wrote: On Thursday, 5 April 2018 at 09:07:52 UTC, Seb wrote: FYI: The problem isn't chunks, but that strings aren't bi-directional ranges (hello ugly auto-decoding!). "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".byCodeUnit Thanks! Very appropriate because it's all hex digits anyway. Instead of std.experimental.all, one can also import std.utf. Initially, I wondered whether autodecoding was the issue here, but I dismissed it because the OP's example calls retro immediately on a string, which is supposedly not autodecodable as bi-directional. But I should examine retro's implementation because I remember several Phobos functions having special cases for strings (which is exactly the issue of auto-decoding). Well sorry for my poor words. Strings are bi-directional ranges, but they aren't random-access nor have a length which is typically required by other ranges to forward bidirectionality. chunks requires hasSlicing + hasLength: https://github.com/dlang/phobos/blob/193c61d985a9645014b2161b59ddb8692308e063/std/range/package.d#L7851 slide requires just hasSlicing: https://github.com/dlang/phobos/blob/193c61d985a9645014b2161b59ddb8692308e063/std/range/package.d#L8650 Now why does "aa"[0.. 1] work, but hasSlicing return false? Because it's explicitly excluded: https://github.com/dlang/phobos/blob/193c61d985a9645014b2161b59ddb8692308e063/std/range/primitives.d#L1557 tl;dr: if you want to do anything useful with strings, byCodeUnit is usually your best friend.
Re: merkle reverse
On Thursday, 5 April 2018 at 09:07:52 UTC, Seb wrote: FYI: The problem isn't chunks, but that strings aren't bi-directional ranges (hello ugly auto-decoding!). "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".byCodeUnit Thanks! Very appropriate because it's all hex digits anyway. Instead of std.experimental.all, one can also import std.utf. Initially, I wondered whether autodecoding was the issue here, but I dismissed it because the OP's example calls retro immediately on a string, which is supposedly not autodecodable as bi-directional. But I should examine retro's implementation because I remember several Phobos functions having special cases for strings (which is exactly the issue of auto-decoding). -- Simon
Re: merkle reverse
On Thursday, 5 April 2018 at 08:57:11 UTC, SimonN wrote: On Thursday, 5 April 2018 at 08:12:38 UTC, aerto wrote: This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4 Here's one solution with std.range.chunks. A small downside is that it needs the array allocation in the middle because chunks cannot offer the bi-directional range necessary for retro. import std.range; import std.algorithm; void main() { string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; assert (merkle.retro.equal( "b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4")); assert (merkle.chunks(2).array.retro.joiner.equal( "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a")); } -- Simon FYI: The problem isn't chunks, but that strings aren't bi-directional ranges (hello ugly auto-decoding!). Simply disable it with byCodeUnit: --- import std.experimental.all; void main() { "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".byCodeUnit.chunks(2).retro.joiner.writeln; "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".byCodeUnit.slide(2, 2).retro.joiner.writeln; } --- Oh and the new slide is a generalization of chunks. https://run.dlang.io/is/ggrh14
Re: merkle reverse
05.04.2018 11:57, SimonN пишет: Here's one solution with std.range.chunks. A small downside is that it needs the array allocation in the middle because chunks cannot offer the bi-directional range necessary for retro. import std.range; import std.algorithm; void main() { string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; assert (merkle.retro.equal( "b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4")); assert (merkle.chunks(2).array.retro.joiner.equal( "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a")); } -- Simon It's a pity that retro can't work with chunks without array, it would be really nice!
Re: merkle reverse
On Thursday, 5 April 2018 at 08:12:38 UTC, aerto wrote: This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4 Here's one solution with std.range.chunks. A small downside is that it needs the array allocation in the middle because chunks cannot offer the bi-directional range necessary for retro. import std.range; import std.algorithm; void main() { string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; assert (merkle.retro.equal( "b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4")); assert (merkle.chunks(2).array.retro.joiner.equal( "3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a")); } -- Simon
merkle reverse
This is the bitcoin genesis block merkle root 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b how i can get it at this format 3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a ?? i try it using string merkle = "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"; writeln(merkle.retro.text); and it gives me b33adedfa7b7212ba77cc2e37667f816f78cb13c88a81523a3f98baab4e1e5a4