Re: Slices and Dynamic Arrays
On Monday, January 01, 2018 05:06:46 Tony via Digitalmars-d-learn wrote: > On Monday, 1 January 2018 at 02:10:14 UTC, Jonathan M Davis wrote: > > The DLang Tour should probably be fixed to use the term dynamic > > array though. > > Or embrace both terms but take care that it is clear that they > are synonyms and one may be preferred depending on context. As a > beginner, I had some confusion seeing both terms used. > > There is dual terminology in use outside of dlang.org. The book > Programming In D says: > > Slice: Another name for dynamic array. > > When I write slice I will specifically mean a slice; and when I > write array, I will mean either a slice or a fixed-length array, > with no distinction. > > Slices > > Slices are the same feature as dynamic arrays. They are called > dynamic arrays for being used like arrays, and are called slices > for providing access to portions of other arrays. They allow > using those portions as if they are separate arrays. > --- A big problem with the term slice though is that it means more than just dynamic arrays - e.g. you slice a container to get a range over it, so that range is a slice of the container even though no arrays are involved at all. So, you really can't rely on the term slice meaning dynamic array. Whether it does or not depends on the context. That means that the fact that a number of folks have taken to using the term slice to mean T[] like the D Slices article talks about tends to create confusion when the context is not clear. IMHO, the D Slices article should be updated to use the correct terminology, but I don't think that the author is willing to do that. - Jonathan M Davis
Re: Slices and Dynamic Arrays
On Monday, 1 January 2018 at 02:10:14 UTC, Jonathan M Davis wrote: The DLang Tour should probably be fixed to use the term dynamic array though. Or embrace both terms but take care that it is clear that they are synonyms and one may be preferred depending on context. As a beginner, I had some confusion seeing both terms used. There is dual terminology in use outside of dlang.org. The book Programming In D says: Slice: Another name for dynamic array. When I write slice I will specifically mean a slice; and when I write array, I will mean either a slice or a fixed-length array, with no distinction. Slices Slices are the same feature as dynamic arrays. They are called dynamic arrays for being used like arrays, and are called slices for providing access to portions of other arrays. They allow using those portions as if they are separate arrays. ---
Re: How do you safely deal with range.front?
On 12/30/2017 11:00 AM, aliak wrote: Instead of this: auto result = range.op!f; if (!result.empty) { result.front.method(); } This: range.op!f.ifFront.method(); In the above scenario I only want method to be called if the pipeline resulted in any element left in the range. If you're fine with specifying the function as a template argument, the following works. (As seen with 's => s.foo()' below, you have to use a lambda for member functions anyway.) auto ifFront(alias func, R)(R range) { import std.traits : isArray; static if (isArray!R) { import std.array : empty, front; } if (!range.empty) { func(range.front); } } unittest { size_t executed; struct S { size_t *e; this(ref size_t e) { this.e = &e; } void foo() { ++(*e); } } auto foo(int) { ++executed; } // Non-empty array; should be called auto a = [1]; a.ifFront!foo; assert(executed == 1); // Empty array; should not be called int[] b; b.ifFront!foo; assert(executed == 1); // Non-empty S array; should be called auto c = [ S(executed) ]; c.ifFront!(s => s.foo()); assert(executed == 2); // Empty S array; should not be called S[] d; d.ifFront!(s => s.foo()); assert(executed == 2); } void main() { } Ali
Re: How do you safely deal with range.front?
On Sunday, December 31, 2017 01:03:17 Tony via Digitalmars-d-learn wrote: > For me, front() should throw a pre-defined exception when called > on an empty range in order to eliminate undefined behavior. It > does take some time to make a check, but D does array bounds > checking by default. Ideally the front() check could be turned > off somehow ("-boundschecks=off") by the user for those who want > maximum speed, but I guess there is no way to do that when using > pre-compiled functions in a library. Except that the reason for arrays throwing RangeErrors when you try and index them out-of-bounds is to avoid memory safety issues, which is not necessarily the case at all when you're talking about ranges. Having ranges in general be checking empty in front, popFront, back, etc. would add unnecessary overhead - especially when you consider that ranges often wrap other ranges. You'd be layering on check after check when the calling code is already supposed to be checking empty when necessary to make sure that the range isn't empty. You'd even be layering checks on top of the checks that arrays already do, since many ranges are ultimately wrapped around a dynamic array at their core. The extra checks on arrays avoid nasty memory-related problems and don't involve layering on extra checks all over the place, whereas ranges in general do not pose a memory safety problem (those that do should do checks like dynamic arrays do, but that's not the norm). As for -boundschecks=off, that arguably shouldn't even exist. It can already be gotten around using the ptr property if you really want that extra speed, and the vast majority of programs shouldn't even consider using it, because skipping the bounds checking in arrays is just begging for memory corruption problems. - Jonathan M Davis
Re: Slices and Dynamic Arrays
On Sunday, December 31, 2017 14:49:40 Tony via Digitalmars-d-learn wrote: > On Sunday, 31 December 2017 at 14:24:40 UTC, Jonathan M Davis > > wrote: > > The D Slices article does an excellent job of explaining all of > > this. It's just that it calls the GC-allocated memory buffer > > the dynamic array instead of calling T[] the dynamic array like > > the language and spec do. Regardless, all non-null dynamic > > arrays are slices of memory. > > The DLang Tour also uses the term slice to refer to T[]. > > "The type of arr is int[], which is also called a slice." > > "A slice consists of two members - a pointer to the starting > element and the length of the slice:" Presumably, because whoever wrote that preferred the terminology used in the D Slices article. Regardless, it's not wrong to call them slices. It's just less precise, since the term slice refers to more than dynamic arrays. The DLang Tour should probably be fixed to use the term dynamic array though. - Jonathan M Davis
Re: take symbol as parameter
On Saturday, 30 December 2017 at 23:30:02 UTC, rjframe wrote: On Sat, 30 Dec 2017 13:07:49 +, Marc wrote: how do I take a symbol as parameter? for example: template nameof(alias S) { import std.array : split; enum nameof = S.stringof.split(".")[$-1]; } Works fine for say a enum member such nameof!(myEnum.X) but this: struct S { int v; } S s; writefln(nameof!(s.v)); // should return "v" return the following error: Error: template instance nameof!(v) cannot use local 'v' as parameter to > non-global template nameof(alias S) You can use the name of the struct rather than the instance. writefln(nameof!(S.v)); How do I make it work when the symbol is defiend as following: class C { int a() { return 0; }} call to nameof!(C.a) give compiler error: Error: need 'this' for 'a' of type 'int()' template instance foo.nameof!(a) error instantiating
Re: take symbol as parameter
On Sunday, 31 December 2017 at 22:50:12 UTC, Marc wrote: On Saturday, 30 December 2017 at 23:30:02 UTC, rjframe wrote: On Sat, 30 Dec 2017 13:07:49 +, Marc wrote: how do I take a symbol as parameter? for example: [...] Works fine for say a enum member such nameof!(myEnum.X) but this: [...] return the following error: [...] You can use the name of the struct rather than the instance. writefln(nameof!(S.v)); it doesn't work for me: Error: template instance nameof!(v) cannot use local 'v' as parameter to non-global template nameof(alias S) Put it at global scope. Worked fine.
Re: take symbol as parameter
On Saturday, 30 December 2017 at 23:30:02 UTC, rjframe wrote: On Sat, 30 Dec 2017 13:07:49 +, Marc wrote: how do I take a symbol as parameter? for example: template nameof(alias S) { import std.array : split; enum nameof = S.stringof.split(".")[$-1]; } Works fine for say a enum member such nameof!(myEnum.X) but this: struct S { int v; } S s; writefln(nameof!(s.v)); // should return "v" return the following error: Error: template instance nameof!(v) cannot use local 'v' as parameter to > non-global template nameof(alias S) You can use the name of the struct rather than the instance. writefln(nameof!(S.v)); it doesn't work for me: Error: template instance nameof!(v) cannot use local 'v' as parameter to non-global template nameof(alias S)
std.file and non-English filename in Windows
In Windows, exists, rename, copy will report file not exists when you input non-English filename, such as Chinese 中文.txt
Re: How do you safely deal with range.front?
On 12/31/2017 02:14 PM, aliak wrote: Also, is going out of array bounds well defined behavior in D even with boundscheck off? No. Without the checks you get undefined behavior. I.e., `-boundscheck=off` defeats the `@safe` attribute. For that reason, I'd advise against ever using it. Definitely don't think of it as a harmless optimization switch.
Re: Determine at compile time whether or not an alias is defined in a struct/class
On 12/31/17 10:01 AM, ktoast wrote: Hello everyone, I started to learn D a few weeks ago and have been stuck trying to solve the following problem : - determine at compile time whether an alias is defined or not in a struct/class. You'll find my attempt thereafter, something similar to how it's done in C++ (using the type void_t and partial specialization of a templated struct) : alias void_t(T) = void; struct define_default_type(T) { static struct test(U, V = void) { static const bool value = false; } static struct test(U, V : void_t!(U.default_type)) { static const bool value = true; } static const bool value = test!(T).value; } unittest { struct S { alias default_type = void; } assert(define_default_type!S.value); //define_default_type!S.value is false, not sure why } I can't tell what's wrong with the code above or if this is even the right way to go about it with D. Would anyone have pointers to give me on how to solve this ? Thanks a lot ! hm... what it looks like you are trying to do is find out if the struct has a member default_type, and if it is an alias to a type? It's hard to tell because of your C++-like attempt :) This is how I would do it: enum define_default_type(S) = is(S.default_type); an isexpression has a lot of power: https://dlang.org/spec/expression.html#IsExpression The default iexpression just returns true if the given symbol is a type. So now: assert(define_default_type!S); or even better: static assert(define_default_type!S); // check at compile-time See if it fits your needs. If it doesn't do quite what you want, there are a lot of goodies here: https://dlang.org/spec/traits.html and here: https://dlang.org/phobos/std_traits.html -Steve
Re: How do you safely deal with range.front?
On Sunday, 31 December 2017 at 13:14:10 UTC, aliak wrote: On Sunday, 31 December 2017 at 01:03:17 UTC, Tony wrote: For me, front() should throw a pre-defined exception when called on an empty range in order to eliminate undefined behavior. It does take some time to make a check, but D does array bounds checking by default. Ideally the front() check could be turned off somehow ("-boundschecks=off") by the user for those who want maximum speed, but I guess there is no way to do that when using pre-compiled functions in a library. That sounds like a good idea. Wouldn't the same apply to array bounds checking for precompiled functions though? Yeah, seems like the standard library must be doing one or the other (bounds checking array indexes or not bounds checking them) all the time, depending on how it was compiled. Also, is going out of array bounds well-defined behavior in D even with bounds check off? I'm no expert, but I can't think of how it could be. And any links to docs on UB in D? This thread was the first time I have heard it used with regard to D.
Determine at compile time whether or not an alias is defined in a struct/class
Hello everyone, I started to learn D a few weeks ago and have been stuck trying to solve the following problem : - determine at compile time whether an alias is defined or not in a struct/class. You'll find my attempt thereafter, something similar to how it's done in C++ (using the type void_t and partial specialization of a templated struct) : alias void_t(T) = void; struct define_default_type(T) { static struct test(U, V = void) { static const bool value = false; } static struct test(U, V : void_t!(U.default_type)) { static const bool value = true; } static const bool value = test!(T).value; } unittest { struct S { alias default_type = void; } assert(define_default_type!S.value); //define_default_type!S.value is false, not sure why } I can't tell what's wrong with the code above or if this is even the right way to go about it with D. Would anyone have pointers to give me on how to solve this ? Thanks a lot !
Re: Slices and Dynamic Arrays
On Sunday, 31 December 2017 at 14:24:40 UTC, Jonathan M Davis wrote: The D Slices article does an excellent job of explaining all of this. It's just that it calls the GC-allocated memory buffer the dynamic array instead of calling T[] the dynamic array like the language and spec do. Regardless, all non-null dynamic arrays are slices of memory. The DLang Tour also uses the term slice to refer to T[]. "The type of arr is int[], which is also called a slice." "A slice consists of two members - a pointer to the starting element and the length of the slice:"
Re: Slices and Dynamic Arrays
On Sunday, December 31, 2017 01:57:58 Tony via Digitalmars-d-learn wrote: > On Friday, 29 December 2017 at 23:13:20 UTC, Jonathan M Davis > > wrote: > > The term "slice" is a bit overused in D, meaning a variety of > > things. It doesn't help that some folks dislike the official > > terminology. In general, a slice is a contiguous group of > > elements. A slice of memory would be a contiguous block of > > memory. A dynamic array therefore refers to a slice of memory > > and could be called a slice, but it's also the case that using > > the slice operater on a container is called slicing - e.g. > > rbt[] would give you a range over the container rbt, and that > > range is a slice of the container, but it's not an array at all. > > For me, it is confusing to use "slice" and "dynamic array" as > synonyms. My initial impression was that they must have different > code underlying them, and different behavior. I would pick one or > the other. It should be: > > D Arrays >- Static >- Dynamic > > or > > D Arrays > - Static > - Slice > > > The DLang Tour has a section on Slices that says in bold "Slices > and dynamic arrays are the same". I think that sentence deserves > an explanation as to why there are two terms being utilized for > the same thing. I would prefer that "slice" as a noun was used > only for the time when a dynamic array was initialized from a > slice of another array. Or better yet - slice was never used as a > noun - only a verb or adjective: took a slice of array A to form > a slice dynamic array B (or slice-intialized dynamic array B). > > D Arrays > - Static > - Dynamic >- Slice-Initialized Dynamic All dynamic arrays are slices of memory. What changes is what memory they're sliced from. There is no master dynamic array that controls the memory that backs all of these dynamic arrays. They're the same whether they were allocated via new or slices from a static array or sliced from pointers or whatever. _All_ a dynamic array is a pointer and a length - e.g. struct DynamicArray(T) { size_t length; T* ptr; } It has no mechanism for managing memory or tracking who owns it. All of that is handled by whatever allocated the memory in the first place. In most cases, that's the GC, but it doesn't have to be. The dynamic array doesn't even have a way to keep track of its capacity. All of that is handled by the GC. Yes, appending to a dynamic array or calling reserve on it can cause memory to be allocated by the GC, but that's because the GC looks at the capacity of the array (which it calculates based on extra stuff it keeps track of) and sees whether it can increase the length of the array in place (which it can do only if the array is backed by GC-allocated memory, and the capacity is greater than its current length). The GC then may allocate a new block of memory and copy the contents of the array to the new memory, and the runtime will adjust the two members of the dynamic array so that they point to the new block of memory, but the dynamic array itself does none of this - and it all works exactly the same if the dynamic array is backed by non-GC-allocated memory. It's just that the GC will determine that since it's not backed by GC-allocated memory, its capacity is 0, and any operation that would need to increase the length or capacity of the array will need to reallocate (after which, the dynamic array will be backed by GC-allocated memory regardless of what backed it before). In no case does the dynamic array itself manage its own memory, and there is no concept of the "original" dynamic array that the others come from. As confusing as that may seem at first, that simply isn't how dynamic arrays in D work. Rather than being a container which you can get ranges over, they're a weird hybrid between the two. They have operations that act like they own and manage their own memory, but they really don't. The D Slices article does an excellent job of explaining all of this. It's just that it calls the GC-allocated memory buffer the dynamic array instead of calling T[] the dynamic array like the language and spec do. Regardless, all non-null dynamic arrays are slices of memory. - Jonathan M Davis
Re: Slices and Dynamic Arrays
On Sunday, December 31, 2017 04:42:01 Tony via Digitalmars-d-learn wrote: > On Sunday, 31 December 2017 at 04:20:28 UTC, codephantom wrote: > > On Sunday, 31 December 2017 at 03:57:17 UTC, Tony wrote: > >> On Sunday, 31 December 2017 at 03:08:05 UTC, Ivan Trombley > >> > >> wrote: > >>> double[] D = [3.14159]; > >>> > >>> Can you guess what D is? :D > >> > >> It took me a while but I finally came up with "a slice of pi" > > > > a slice of pi is irrational. > > Even on special occasions? Of course. Cake is so much better. ;) - Jonathan M Davis
Re: static if and early exit from function doesn't seem to work?
On Sunday, 31 December 2017 at 13:32:03 UTC, aliak wrote: So it seems it tries to compile the statements below the check on V.length even though it's guaranteed to be true and there's a return statement inside the if. Yeah, static if includes or excludes code independently at compile time. So what you wrote there would be like, assuming the first to static ifs pass: auto concat(R, V...)(R range, V values) if (isInputRange!R) { import std.range: chain, ElementType; return range; return range.chain(values[0]).concat(values[1..$]); } The code is still there, even if it isn't reached due to an early return, and thus still must compile. Using else static if means it won't be generated.
Re: static if and early exit from function doesn't seem to work?
On Sunday, 31 December 2017 at 13:32:03 UTC, aliak wrote: Alo! I'm making a recursive concat function that is similar to chain. The following code works: [...] I suspect it's because you've no 'else static if'.
static if and early exit from function doesn't seem to work?
Alo! I'm making a recursive concat function that is similar to chain. The following code works: import std.range: isInputRange; auto concat(R, V...)(R range, V values) if (isInputRange!R) { import std.range: chain, ElementType; static if (V.length) { static if (isInputRange!(V[0])) { return range.chain(values[0]).concat(values[1..$]); } else static if (is(V[0] == ElementType!R)) { return range.chain([values[0]]).concat(values[1..$]); } // add an else assert here. } else { return range; } } But the following does not: auto concat(R, V...)(R range, V values) if (isInputRange!R) { import std.range: chain, ElementType; static if (!V.length) { return range; } static if (isInputRange!(V[0])) { return range.chain(values[0]).concat(values[1..$]); } static if (is(V[0] == ElementType!R)) { return range.chain([values[0]]).concat(values[1..$]); } } You get a: Error: tuple index 0 exceeds 0 Error: template instance range.concat.concat!(Result) error instantiating So it seems it tries to compile the statements below the check on V.length even though it's guaranteed to be true and there's a return statement inside the if. Is it a current limitation of static if? or a bug? or is something like this just not possible because of something I'm not seeing? Cheers
Re: How do you safely deal with range.front?
On Sunday, 31 December 2017 at 01:03:17 UTC, Tony wrote: For me, front() should throw a pre-defined exception when called on an empty range in order to eliminate undefined behavior. It does take some time to make a check, but D does array bounds checking by default. Ideally the front() check could be turned off somehow ("-boundschecks=off") by the user for those who want maximum speed, but I guess there is no way to do that when using pre-compiled functions in a library. That sounds like a good idea. Wouldn't the same apply to array bounds checking for precompiled functions though? Also, is going out of array bounds well defined behavior in D even with boundscheck off? And any links to docs on UB in D?
Re: Avoiding GC in D and code consistancy
On 12/31/17 7:50 AM, Steven Schveighoffer wrote: Note, you can use a "sink" version of toString as well, and avoid the gc: void toString(void delegate(const(char)[]) sink) @nogc { // use formatValue to push into the sink } I guess I'm missing some parameters here, go with what Seb linked to :) -Steve
Re: Avoiding GC in D and code consistancy
On 12/31/17 6:16 AM, Tim Hsu wrote: On Sunday, 31 December 2017 at 07:32:50 UTC, Ali Çehreli wrote: On 12/30/2017 11:16 PM, Tim Hsu wrote: > Struct version of Vector3f can't derive toString > method. writeln() prints unformated struct members. I know I can use > helper function here. But is there any other way? The normal way that I know is to insert a function like the following into Vector3f: string toString() { import std.string : format; return format("%s,%s,%s", x, y, z); } > class version of Vector3f. Require new operator in opBinary(). scoped! > won't work here. > > Is there a better to write vector3f class while avoiding GC? Yeah, it doesn't make sense that a type of x, y, z should be a class. I would stay with a struct here. Sorry I am a bit disappointed. It seems writeln itself will check if the struct to be printed has toString. If not, it use default struct printer. Note, you can use a "sink" version of toString as well, and avoid the gc: void toString(void delegate(const(char)[]) sink) @nogc { // use formatValue to push into the sink } -Steve
Re: Slices and Dynamic Arrays
On 12/30/17 10:08 PM, Ivan Trombley wrote: double[] D = [3.14159]; Can you guess what D is? :D An approximation of a slice of pi. -Steve
Re: Slices and Dynamic Arrays
On 12/30/17 8:57 PM, Tony wrote: For me, it is confusing to use "slice" and "dynamic array" as synonyms. My initial impression was that they must have different code underlying them, and different behavior. As stated in the slices article, I think of them as separate -- the slice is the public type that is used to operate on dynamic arrays, the dynamic array is a nameless type that only exists in the runtime. It helped me immensely when rewriting the array runtime to think of it that way. All the feedback I received when publishing the article was along the lines of "Wow, thinking of it that way helps a lot", so I think it's a good mental model. But in terms of D types, the slice *is* the dynamic array type, it behaves in all the ways you would expect a dynamic array type to behave. The only difference is that a slice does not own the memory it references. Normally you would consider a dynamic array to own its memory (i.e. be responsible for allocation and destruction). Because we have the GC, ownership can be fuzzy. The DLang Tour has a section on Slices that says in bold "Slices and dynamic arrays are the same". I think that sentence deserves an explanation as to why there are two terms being utilized for the same thing. I would prefer that "slice" as a noun was used only for the time when a dynamic array was initialized from a slice of another array. Or better yet - slice was never used as a noun - only a verb or adjective: took a slice of array A to form a slice dynamic array B (or slice-intialized dynamic array B). The question really is, what is the name of the type T[]? If you give it a different name depending on how it was created, then you have all sorts of confusion. In fact, there was a proposal by Walter and Andrei a long long time ago to have a type T[new] which would be the dynamic array type, and T[] be the slice type. This failed, because in Andrei's words, "Explaining two very similar but subtly different types to newcomers is excruciatingly difficult." IMO, T[] is a slice, because it may not be GC-backed dynamic array data underneath. Some people prefer to think of it as a dynamic array, because you can use it like a dynamic array no matter what it points at. Either way works, and fits the implementation. It's really a matter of preference. -Steve
Re: Avoiding GC in D and code consistancy
On Sunday, 31 December 2017 at 07:16:46 UTC, Tim Hsu wrote: I came from C++ looking forward to D. Some languages require programmers to use GC all the time. However, A lot of time we don't really need GC especially when the time of destruction is deterministic in compile time. [...] You can use a custom toString method which doesn't do any allocations: https://wiki.dlang.org/Defining_custom_print_format_specifiers However, the building blocks (formattedWrite and writeln) aren't "@nogc" at the moment.
Re: Avoiding GC in D and code consistancy
On Sunday, 31 December 2017 at 07:32:50 UTC, Ali Çehreli wrote: On 12/30/2017 11:16 PM, Tim Hsu wrote: > Struct version of Vector3f can't derive toString > method. writeln() prints unformated struct members. I know I can use > helper function here. But is there any other way? The normal way that I know is to insert a function like the following into Vector3f: string toString() { import std.string : format; return format("%s,%s,%s", x, y, z); } > class version of Vector3f. Require new operator in opBinary(). scoped! > won't work here. > > Is there a better to write vector3f class while avoiding GC? Yeah, it doesn't make sense that a type of x, y, z should be a class. I would stay with a struct here. Ali Sorry I am a bit disappointed. It seems writeln itself will check if the struct to be printed has toString. If not, it use default struct printer.