Re: std.file.read returns void[] why?
On Thursday, 17 April 2014 at 12:59:20 UTC, Steven Schveighoffer wrote: It was never possible. You must explicitly cast to void[]. void[] makes actually little sense as the result of whole-file read that allocates. byte[] is at least usable and more accurate. In fact, it's a little dangerous to use void[], since you could assign pointer-containing values to the void[] and it should be marked as NOSCAN (no pointers inside file data). However, when using the more conventional read(void[]) makes a LOT of sense, since any T[] implicitly casts to void[]. -Steve void[] will only make sense once you've accepted that "void.sizeof == 1". Well, I guess "void[]" is C++'s "char*" for indiscriminate buffers. Speaking of which, does "void*" trigger strict aliasing in D? This subject seems like a hot potato no-one wants to touch.
Re: std.file.read returns void[] why?
On Thursday, 17 April 2014 at 21:27:44 UTC, Steven Schveighoffer wrote: On Thu, 17 Apr 2014 17:04:25 -0400, monarch_dodra wrote: void[] will only make sense once you've accepted that "void.sizeof == 1". It is already accepted that when we talk about length in a void[], it's the number of bytes. But the data has no formal type. Well, I always thought that "void[] slice" meant "there are slice.length items, starting at slice.ptr. I don't know the size of the individual items". For example, in C, a lot of functions take "void* first, size_t num, size_t width". In fact, most of druntime functions take "void[]" buffers that work that way. There's an associated typeid, so that you can now how large each individual items are. But any array implicitly casts to void[]. This is why it makes a good parameter for read or write (when reading or writing the binary data). I guess. I just find it kind of strange that a type "that has no type" would have an actual sizeof. Then again, I thought void had no sizeof in C, but I just checked, and I was wrong. Well, I guess "void[]" is C++'s "char*" for indiscriminate buffers. Speaking of which, does "void*" trigger strict aliasing in D? This subject seems like a hot potato no-one wants to touch. No, it's equivalent to void *, not char *. in D, ubyte[] would be the equivalent of C's char *. -Steve Correct.
Re: std.file.read returns void[] why?
On Friday, 18 April 2014 at 13:08:04 UTC, Steven Schveighoffer wrote: I admit, I didn't think C's void had a size ;) I'm pretty sure it doesn't in D, but then again... -Steve Yeah... "static assert(void.sizeof == 1);" passes :/ So in any case, long story short: "void[]": This is an un-typed buffer, pointing to a memory location that starts at .ptr, and is .length bytes in length. Also, as far as the GC is concerned, "void" is a type that should be scanned (whether or not the data originally allocated was marked as such is another issue).
Re: Reducing an array
On Friday, 18 April 2014 at 20:27:20 UTC, Steven Schveighoffer wrote: Note also that what it returns is not an array, but a lazily iterated range over the array. If you want another array, this is the code I would use: arr.sort(); arr = arr.uniq.array(); -Steve Out of curiosity, if the requirement was to *also* preserve ordering (eg: remove all non-first elements), how would you go at it? [2, 1, 1, 3, 2, 3] => [2, 1, 3]; Maybe std.algorithm's `makeIndex` would help here? Bonus points for doing it inplace.
Re: Reducing an array
On Friday, 18 April 2014 at 22:11:17 UTC, bearophile wrote: monarch_dodra: Out of curiosity, if the requirement was to *also* preserve ordering (eg: remove all non-first elements), how would you go at it? [2, 1, 1, 3, 2, 3] => [2, 1, 3]; Maybe std.algorithm's `makeIndex` would help here? Bonus points for doing it inplace. This preserves ordering and it's in-place. Not tested much: void main() { import std.stdio, std.traits; auto data = [2, 1, 1, 3, 2, 3]; bool[ForeachType!(typeof(data))] seen; size_t pos = 0; foreach (immutable i; 0 .. data.length) if (data[i] !in seen) { if (pos != i) data[pos] = data[i]; seen[data[i]] = true; pos++; } data.length = pos; data.writeln; } Bye, bearophile I thought of an approach somewhere along these lines. I was wondering if there was a UFCS approach too. Or an in-place approach. Well, the "inplace" is easy of you accept N² performance :)
Re: Reducing an array
On Friday, 18 April 2014 at 22:11:17 UTC, bearophile wrote: This preserves ordering and it's in-place. Not tested much: void main() { import std.stdio, std.traits; auto data = [2, 1, 1, 3, 2, 3]; bool[ForeachType!(typeof(data))] seen; size_t pos = 0; foreach (immutable i; 0 .. data.length) if (data[i] !in seen) { if (pos != i) data[pos] = data[i]; seen[data[i]] = true; pos++; } data.length = pos; data.writeln; } Bye, bearophile If you replace that "=" with a swap, then you can also preserve the duplicate elements at the end (although in no specific ordering): import std.stdio : writefln; import std.algorithm : canFind, swap; // void main() { auto arr = [1,1,5,2,3,2,2,4,5,5,1]; size_t pos = 0; foreach(ref e; arr) if (!arr[0 .. pos].canFind(e)) swap(arr[pos++], e); writefln("uniques: %s", arr[0 .. pos]); writefln("dupes: %s", arr[pos .. $]); } // I was trying a "100% inplace" solution, but I found nothing better than N². It's basically still what you submitted though.
Re: Template method and type resolution of return type
On Sunday, 20 April 2014 at 07:52:08 UTC, matovitch wrote: struct S { ubyte get() { return 0 ; } float get() { return 0.; } } void main() { S s; float x = s.get(); // does'nt know which overload, does'nt compile. } What I do find interesting though, is that you are allowed to write the overload, whereas C++ would outright block you for ambiguity "at the source". This means that with proper meta magic eg `__traits(getOverloadSet, S, "get")`, you could, *manually* resolve the ambiguity yourself.
Re: number formatting
On Sunday, 20 April 2014 at 12:53:11 UTC, steven kladitis wrote: Note sure if you can edit messages once sent. $13,456.67 245,678,541 On Sunday, 20 April 2014 at 12:50:52 UTC, steven kladitis wrote: How do you format numbers to have things like. Leading $ or , or with or without leading zeros. for example $56.00 $056.00 $1,3456.67 <345.89>CR Simply add what you want in the format string. For example: double d = 56.55; writefln("$03.5s", d); writefln("<.4s>CR", d); will print "$056.55" "<56.55>CR" I don't know of any "built-in" way to do number grouping. Also, when dealing with monetary amounts, you shouldn't be using doubles (I'm not saying you are), but some other structure specifically designed to track cents. Ideally, such a structure would have built-in "toString" formating.
Re: string -> string literal
On Sunday, 20 April 2014 at 17:55:25 UTC, Ellery Newcomer wrote: is there a function in phobos anywhere that takes a string and escapes it into a string literal suitable for string mixins? something like assert (f("abc\ndef") == "\"abc\\ndef\""); It's a bit hackish, but it avoids deploying code and reinventing anything. You can use format "string-range" formating to print the string escaped. Catch that, and then do it again: string s = "abc\ndef"; writefln("[%s]\n", s); //raw s = format("%(%s%)", [s]); writefln("[%s]\n", s); //escaped s = format("%(%s%)", [s]); writefln("[%s]\n", s); //escapes are escaped As you can see from the output, after two iterations: [abc def] ["abc\ndef"] ["\"abc\\ndef\""] I seem to recall that printing strings "escaped" has been requested before, but, AFAIK, this is the best we are currently providing. Unless you call std.format's "formatElement" directly. However, this is an internal and undocumented function, and the fact it isn't private is probably an oversight.
Re: Function to print a diamond shape
On Monday, 21 April 2014 at 00:11:14 UTC, Jay Norwood wrote: So this printDiamonde2b example had the fastest time of the solutions, and had similar times on all three builds. The ldc2 compiler build is performing best in most examples on ubuntu. void printDiamonde2b(in uint N) { uint N2 = N/2; char pSpace[] = uninitializedArray!(char[])(N2); pSpace[] = ' '; char pStars[] = uninitializedArray!(char[])(N+1); pStars[] = '*'; pStars[$-1] = '\n'; auto w = appender!(char[])(); w.reserve(N*3); foreach (n ; 0 .. N2 + 1){ w.put(pSpace[0 .. N2 - n]); w.put(pStars[$-2*n-2 .. $]); } foreach_reverse (n ; 0 .. N2){ w.put(pSpace[0 .. N2 - n]); w.put(pStars[$-2*n-2 .. $]); } write(w.data); } With this slightly tweaked solution, I can get times of roughly 50% to 100% faster, on my dmd-linux box: // void printDiamonde2monarch(in uint N) { uint N2 = N/2; char[] pBuf = uninitializedArray!(char[])(N + N2); pBuf[ 0 .. N2] = ' '; pBuf[N2 .. $] = '*'; auto slice = uninitializedArray!(char[])(3*N2*N2 + 4*N); size_t i; foreach (n ; 0 .. N2 + 1){ auto w = 1 + N2 + n; slice[i .. i + w] = pBuf[n .. w + n]; slice[(i+=w)++]='\n'; } foreach_reverse (n ; 0 .. N2){ auto w = 1 + N2 + n; slice[i .. i + w] = pBuf[n .. w + n]; slice[(i+=w)++]='\n'; } write(slice[0 .. i]); } // The two "key" points here, first, is to avoid using appender. Second, instead of having two buffer: "" and "**\n", and two do two "slice copies", to only have 1 buffer "*", and to do 1 slice copy, and a single '\n' write. At this point, I'm not sure how we could be going any faster, short of using alloca... How does this hold up on your environment?
Re: Named template constraints
On Tuesday, 22 April 2014 at 15:06:34 UTC, Steven Schveighoffer wrote: Note, is the r2 = R.init needed? Not sure. Yes: It R2 has no default init, or is an immutable, then that line will fail to compile.
Re: Function to print a diamond shape
On Tuesday, 22 April 2014 at 05:05:30 UTC, Jay Norwood wrote: On Monday, 21 April 2014 at 08:26:49 UTC, monarch_dodra wrote: The two "key" points here, first, is to avoid using appender. Second, instead of having two buffer: "" and "**\n", and two do two "slice copies", to only have 1 buffer " *", and to do 1 slice copy, and a single '\n' write. At this point, I'm not sure how we could be going any faster, short of using alloca... How does this hold up on your environment? Yes your solution is the fastest yet. Also, its times are similar for all three compilers. The range of execution times varied for different solutions from over 108 seconds down to 64 msec. I see that RefAppender's data() returns the managed array. Can write() handle that? It seems that would be more efficient than duplicating the character buffer ... I'm not sure what you mean? "data" returns the managed array, but no duplication ever actually happens. It's allocated on the GC. the only thing that is copied is the slice itself. or perhaps writing directly to an OutBuffer, and then sending that to write() would avoid the duplication? appender *is* the outbuffer :)
Re: Function to print a diamond shape
On Tuesday, 22 April 2014 at 11:41:41 UTC, Jay Norwood wrote: Wow, joiner is much slower than join. Such a small choice can make this big of a difference. Not at all expected, since the lazy calls, I thought, were considered to be more efficient. This is with ldc2 -O2. Yeah, that's because join actually works on "RoR, R", rather than "R, E". This means if you feed it a "string[], string", then it will actually iterate over individual *characters*. Not only that, but since you are using char[], it will decode them too. "join" is faster for 2 reasons: 1) It detects you want to joins arrays, so it doesn't have to iterate over them: It just glues them "slice at once" 2) No UTF decoding. I kind of wish we had a faster joiner, but I think it would have made the call ambiguous.
Re: Named template constraints
On Tuesday, 22 April 2014 at 15:30:36 UTC, Steven Schveighoffer wrote: On Tue, 22 Apr 2014 11:15:14 -0400, monarch_dodra wrote: On Tuesday, 22 April 2014 at 15:06:34 UTC, Steven Schveighoffer wrote: Note, is the r2 = R.init needed? Not sure. Yes: It R2 has no default init, or is an immutable, then that line will fail to compile. I don't believe it's possible to have no 'init'. I think the reason it says '= R.init' is for ranges that have @disable this(). Yes, that's what I meant by "no default init". Guess I got my terms wrong. Sorry. Also, an immutable can be initialized that way: immutable int[] = int[].init; Isn't that exactly "R.init" ? Of course, it wouldn't pass the rest of isInputRange. -Steve In this particular case, probably not (except for, maybe "repeat"?) In any case, it's become the "generic" way of initializing a generic type.
Re: The lifetime of reduce's internal seed
On Tuesday, 22 April 2014 at 17:31:22 UTC, Ali Çehreli wrote: I opened the following bug before reading reduce's documentation carefully: https://issues.dlang.org/show_bug.cgi?id=12610 import std.stdio; import std.algorithm; void main() { int[] arr = [ 0 ]; int[1] seed; int[] result = reduce!((sum, _) => sum[])(seed, arr); writefln("%s", result); } The output is garbage like [373728176]. Note that the original seed is a value type, which is later sliced by the lambda. Now I think that it can be considered a user error. Do you agree whit that? If so, this is something else we should be careful about similar to the internal buffer of byLine. Ali I see one user bug, and one language bug, but no library issues. The user bug is the lambda, that returns a reference to a local ("sum[]"). That said, I do believe the compiler should be able to catch think. The "int[] reduce...", however, I think is a outright language issue. Implicilty calling opSlice on a static array is one thing, but doing it on an rvalue is an outright aberration. The code should be rejected no questions asked.
Re: The lifetime of reduce's internal seed
On Tuesday, 22 April 2014 at 18:34:47 UTC, Steven Schveighoffer wrote: On Tue, 22 Apr 2014 14:17:57 -0400, Ali Çehreli wrote: I don't think there is slicing an rvalue though. (?) reduce() is taking a copy of the seed and then returning a slice to it because the user slices it in their lambda. It effectively does the following, which unfortunately compiles: int[] foo() { int[1] sum; return sum[];// <-- no warning } It's not slicing an rvalue, but the above is trivially no different than: In this case no, but; // int[1] foo(); int[] a = foo(); // *is* slicing an rvalue, and it *does* compile. I don't think there needs to be escape analysis to catch this.
Re: The lifetime of reduce's internal seed
On Tuesday, 22 April 2014 at 18:17:58 UTC, Ali Çehreli wrote: On 04/22/2014 11:03 AM, monarch_dodra wrote: > The "int[] reduce...", however, I think is a outright language issue. > Implicilty calling opSlice on a static array is one thing, but doing it > on an rvalue is an outright aberration. The code should be rejected no > questions asked. I don't think there is slicing an rvalue though. (?) reduce() is taking a copy of the seed and then returning a slice to it because the user slices it in their lambda. It effectively does the following, which unfortunately compiles: int[] foo() { int[1] sum; return sum[];// <-- no warning } Reduce returns "the seed". It's actually doing something more like this: int[1] foo() { int[1] sum sum = sum[]; //The lambda operates, and the //result is assigned back to the seed. return sum; //Returns the seed. } So when writing: void main() { int[] result = foo(); } There's a *second* level of bug. (assigning an rvalue "int[1]" to int[]) *This* works fine though: int[1] seed; int[1] result = reduce!((ref sum, _) => sum)(seed, arr); BTW, I'm re-implemented reduce recently (not yet pulled), but I was *very* thorough about documenting what it does: https://github.com/D-Programming-Language/phobos/pull/2060 Could you take a look at it (the documentation I mean), and tell me if everything is what you would have expected?
Re: Named template constraints
On Tuesday, 22 April 2014 at 18:35:58 UTC, Steven Schveighoffer wrote: On Tue, 22 Apr 2014 11:36:07 -0400, monarch_dodra wrote: On Tuesday, 22 April 2014 at 15:30:36 UTC, Steven Schveighoffer wrote: Also, an immutable can be initialized that way: immutable int[] = int[].init; Isn't that exactly "R.init" ? Yes, you said if it's an immutable it would fail to compile. I think this is not true. -Steve Ah... you said: Note, is the r2 = R.init needed? Not sure. To whitch I replied: Yes: It R2 has no default init, or is an immutable, then that line will fail to compile. I meant that if you *don't* add the R.init, then the code will *not* compile. EG => R.init is necessary. Sorry for the mixup :/
Re: The lifetime of reduce's internal seed
On Tuesday, 22 April 2014 at 18:49:41 UTC, Steven Schveighoffer wrote: On Tue, 22 Apr 2014 14:47:19 -0400, monarch_dodra wrote: In this case no, but; // int[1] foo(); int[] a = foo(); // *is* slicing an rvalue, and it *does* compile. I don't think there needs to be escape analysis to catch this. Oh yeah, that's bad. -Steve It's filed: https://issues.dlang.org/show_bug.cgi?id=12625 I hope it gets fixed. I really see no justification for it.
Re: Partial ordering of constructors with type parameters
On Wednesday, 23 April 2014 at 16:44:37 UTC, Charles McAnany wrote: Friends, I have a class that needs two constructors: class Foo{ this(int x){} this(T)(T x) if(!is(T == int)){} } void main(){} But this does not compile because the two constructors conflict: buggy.d(3): Error: template buggy.Foo.__ctor(T)(T x) if (!is(T == int)) conflicts with constructor buggy.Foo.this at buggy.d(2) Of course, I can just have one constructor that doesn't have the constraint and then use a static if to redirect to a private method, but that seems clunky to me. (not to mention it would complicate the documentation.) Any ideas? Cheers, Charles McAnany. Update your compiler. What version are you on? This was resolved in the 2.064 release. You don't even need the "if(!is(T == int))", since non-template takes precendence. // class Foo{ this(int x){} this(T)(T x) {} } void main() { auto a = new Foo(5); } // If you can't update your compiler, an alternative is to make your non-template version an actual template: class Foo{ this(T : int)(T x){} this(T)(T x) {} }
Re: Partial ordering of constructors with type parameters
On Wednesday, 23 April 2014 at 22:07:32 UTC, John Colvin wrote: On Wednesday, 23 April 2014 at 18:04:05 UTC, monarch_dodra wrote: If you can't update your compiler, an alternative is to make your non-template version an actual template: class Foo{ this(T : int)(T x){} this(T)(T x) {} } I haven't tested, but wouldn't this be more precisely equivalent?: class Foo{ this()(int x){} this(T)(T x) {} } *That* creates a conflict though :/
Re: Partial ordering of constructors with type parameters
On Thursday, 24 April 2014 at 10:12:15 UTC, Andrej Mitrovic via Digitalmars-d-learn wrote: On 4/24/14, monarch_dodra via Digitalmars-d-learn wrote: *That* creates a conflict though :/ Are you sure? I can't reproduce. Weird. I can't either. I probably accidentally tested it on 2.063? Who cares; yes, it's more practical.
Re: The lifetime of reduce's internal seed
On Saturday, 26 April 2014 at 06:24:26 UTC, Ali Çehreli wrote: On 04/22/2014 11:45 AM, monarch_dodra wrote: > Reduce returns "the seed". It's actually doing something more like this: > > int[1] foo() > { > int[1] sum > sum = sum[]; //The lambda operates, and the > //result is assigned back to the seed. > return sum; //Returns the seed. > } My original lambda that returned a slice was correct then. The seed would eventually be copied out. Had the compiler not allow slicing the rvalue then I would be in good shape. Well... your lambda *was* returning a slice to its local copy of sum. So I thin kit is still wrong. "(ref sum, _) => sum[]" would have been correct though. > BTW, I'm re-implemented reduce recently (not yet pulled), but I was > *very* thorough about documenting what it does: > https://github.com/D-Programming-Language/phobos/pull/2060 > > Could you take a look at it (the documentation I mean), and tell me if > everything is what you would have expected? I think it looks great! :) Two comments/questions which I did not make on github: 1) Some of the documentation comments that are inside a scope are not formatted as such. For example, this comment does not start with /++ : https://github.com/monarchdodra/phobos/blob/reduceReimpl/std/algorithm.d#L753 I wonder whether they are still included in the produced documentation. Nope, that was a mistake on my part. Good catch. 2) I think even single-line code blocks should have curly brackets but Phobos code does not follow that guideline. :) Ali It depends I say. I usually do that, but for certain functions, such as reduce, it would *literally* double the amount of lines required to write it. I that point, the function becomes long enough for it to be a readability problem.
Re: Can I circumvent nothrow?
On Sunday, 27 April 2014 at 08:04:54 UTC, Andrej Mitrovic via Digitalmars-d-learn wrote: On 4/27/14, Damian Day via Digitalmars-d-learn wrote: So I have this procedure. Have a look at std.exception.assumeWontThrow: http://dlang.org/phobos/std_exception.html#.assumeWontThrow Keep in mind that "assume won't throw" will assert *should* an exception actually be thrown. If the function actually can and will throw, but you simply don't care, you'd need a "squelchException" (which we don't have), or more simply, just: // try { myCode(); } catch (Exception){} //
Re: Trailing commas in constructor arguments?
On Sunday, 4 May 2014 at 10:04:26 UTC, Gary Willoughby wrote: In the following snippet is the line marked WOAH legal? The compiler doesn't complain about the trailing comma in the constructor arguments. import std.stdio; class Foo { public this(string foo) { } } void main(string[] args) { auto foo = new Foo("bar", ); // <-- WOAH } Yes. As a rule of thumb, a single trailing comma is *always* legal. It allows for easier and uniform syntax for calls with lots of arguments: new Foo( "bar1", "bar2", "bar3", "bar4", ); This works for mostly anything: both calls and function declaration: this( string arg1, string arg2, string arg3, string arg4, ) { ... } It also works for arrays: auto arr1= [ 1, 2, 3, 4, ]; Or enums: enum Letters { A, B, C, D, } The advantage in all the above means no special case if you want to add, swap or comment a certain argument: They are all "equal" in terms of separator comma. Finally, it makes mixins/generated code easier, since you don't have to worry about the "last argument" special case (though if you use "range formating": "%(%s,%)", it shouldn't matter). So long story short, yes, it is legal. And convenient. I've personally adopted it, and use it any time I list arguments vertically.
Re: Is this a bug?
On Sunday, 4 May 2014 at 09:42:17 UTC, Alex wrote: Hello, I am trying to use the std.log module that is here: https://github.com/linkrope/log.d And I encountered a segmentation fault using dmd 2.065 on a Linux 64 platform. The reduced test case is this: // import std.stdio; import std.log; private class CHello { ~this() { info("info - destructor"); //info, warning, error segfault; however, writefln works } } void main(string[] args) { CHello chello = new CHello(); } // Is this a bug? Maybe, maybe not. As rule of thumb, you can't allocate during a GC cleaning cycles, and class destructors are usually called during a GC cleaning cycle. This means it is usually unsafe to call *anything* that could potentially allocate in a destructor. I don't know the details of the log module. AFAIK, the code itself doesn't *seem* to allocate anything to just log, but it does seem to use a singleton logger object. Could you try to log a single "info" in your main, and see if it resolves the issue? We'd need to contact the author directly too about this issue.
Re: Is this a bug?
On Sunday, 4 May 2014 at 10:28:30 UTC, Mike Parker wrote: The current implementation of the GC will run destructors on any objects still resident on the heap during termination. There is no way to guarantee the order in which those destructors will be run. Most likely, what you're seeing is that the LogFilter instance referenced by the info template is being destroyed before the destructor on CHello is run. Therefore, you're referencing an invalid memory location. The short of it is that you should never touch anything on that lives on the GC heap from inside a destructor -- there's no guarantee that it will still be alive when your destructor is run. Really??? I knew there was no guarantee in which order the destructor were run, but at the very least, I thought you had a guarantee of dependency ordering? ... Then again, the GC can collect cycles, so... Well dang. That's a bummer.
Is my T.init elaborate (eg: Not "0")
I'm looking for a way, to *statically* know if my type's ".init" value is nothing but zeros. I need this to initialize a dynamic array: If the T.init is nothing but 0, then I can just memset the whole array in a single call. Otherwise, I have to memcpy T.init individually N times. Currently, I can (runtime) use "typeid(T).init.ptr": Types that don't have an an elaborate .init will return null. I'm trying to find the same result, without a runtime check. Anybody know how? I'd write a function that tests the bits of a T.init copy, but reinterpreting is not allowed during CTFE...
Re: Is my T.init elaborate (eg: Not "0")
On Monday, 5 May 2014 at 21:54:33 UTC, Tobias Pankrath wrote: On Monday, 5 May 2014 at 21:51:14 UTC, Tobias Pankrath wrote I'm trying to find the same result, without a runtime check. Anybody know how? I'd write a function that tests the bits of a T.init copy, but reinterpreting is not allowed during CTFE... Foreach member x of Type X of T, check if T.init.x equals X.init? Ah, sorry, didn't read carefully. This is not what you want. Actually, I think you're on to something. I can recursively iterate on all basic types in my T, and check they are all "0" or NULL. Should work. Thanks!
Re: Implicit static->dynamic arr and modifying
On Wednesday, 7 May 2014 at 20:09:22 UTC, H. S. Teoh via Digitalmars-d-learn wrote: On Wed, May 07, 2014 at 06:31:15PM +, Rene Zwanenburg via Digitalmars-d-learn wrote: On Wednesday, 7 May 2014 at 15:41:19 UTC, Nick Sabalausky wrote: >On 5/6/2014 6:46 PM, Rene Zwanenburg wrote: [...] >>struct S >>{ >>@safe: >>string str; >> >>this(string data) >>{ >>import std.digest.md; >>str = md5Of(data).toHexString(); // Oops... >>} >>} > >That must be a terribly subtle one, I'm not seeing the >problem at >all. > >I get that md5Of returns a static array, and then a slice of >it gets >passed to toHexString, but AIUI toHexString finishes (and >returns a >newly allocated string) before the temporary static array >leaves >scope. toHexString has an overload that takes a static array and can therefore return a static array (the length is known to be twice the input length). In essence it's the same bug as directly storing the result of md5Of, but this was the exact line that was causing me grief. Indeed, it looks innocent enough.. So, toHexString returns a static array, which can be implicitly assigned to a member slice. In @safe code. I was horrified ;). Imo it's one of the most serious violations of D's safe by default principle. Ouch!! Wow, that's really nasty. :-( It totally went by me, even though I've been bitten before by the variadic ctor bug. T FYI, I think this is one of the biggest implicit static array=>dynamic array bug you can do. What's more, slicing of an rvalue static arrays is wrong 100% of the time. It's taking the address of a temporary. And the compiler should be able to catch it easy-peasy. I filed this one: https://issues.dlang.org/show_bug.cgi?id=12625 implicit slicing of RValue static array should be illegal While I do (kinda) agree we can't deprecate static array to dynamic array implicit conversion, THIS is one case we should ban. It's *never* correct. Always a bug.
Re: throws Exception in method
On Thursday, 8 May 2014 at 13:06:05 UTC, amehat wrote: Okay. Thank you for these explanations, I understand a little better the exceptions D. Keep in mind that D also has the concept of "Error". Both "Exception" and "Error" derive from "Throwable". "nothrow" only means the function will not throw an *Exception*. "Error" can be thrown any time, from anywhere. They bypass the nothrow, bypass destructor cleanup, and fly past "catch (Exception)". An Error is basically: "A critical Error has occurred. Salvage what you can before dying."
Re: why can't I call const methods on shared objects?
On Friday, 9 May 2014 at 21:58:41 UTC, Steven Schveighoffer wrote: On Fri, 09 May 2014 17:45:37 -0400, Vlad Levenfeld wrote: Is there any way to declare a method as "safe regardless of shared/mutability/etc" (or some other way to avoid cast(Type)object.property every time I want to check a property which won't affect any state)? Not really for shared. For everything else, there's const for value properties, and inout for reference properties. Shared is quite different, because the method has to be cognizant of race conditions. It has to be implemented differently. Casting away shared is somewhat dangerous, but OK if you logically know there is no race condition. -Steve You could just declare the function as "immutable". But then, it'll only work on immutable types. But then again, that would be the only way to actually statically and safely guarantee there are no race conditions.
Re: Why std.algorithm.sort can't be applied to char[]?
On Monday, 12 May 2014 at 18:44:22 UTC, Jonathan M Davis via Digitalmars-d-learn wrote: Sure, you can cast char[] to ubyte[] and sort that if you know that the array only holds pure ASCII. In fact, you can use std.string.representation to do it - e.g. auto ascii = str.representation; and if str were mutable, then you could sort it. But that will only work if the string only contains ASCII characters. Regardless, he wanted to know why he couldn't sort char[], and I explained why - all strings are treated as ranges of dchar, making it so that if their element type is char or wchar, so they're not random access and thus can't be sorted. Arguably, a smart enough implementation should know how to sort a "char[]", while still preserving codepoint integrity. As a matter of fact, the built in "sort" property does it. void main() { char[] s = "éöeèûà".dup; s.sort; writeln(s); } //prints: eàèéöû
Re: Array!T and find are slow
On Wednesday, 14 May 2014 at 14:54:57 UTC, David Nadlinger wrote: On Wednesday, 14 May 2014 at 14:24:28 UTC, Damian Day wrote: I've written some search functions, which are many times faster, is it worth making a pull request? Generally, we strive to make the algorithms in Phobos as fast as possible even in the general case. I didn't look at the issue at hand in any detail, but if the "-O -release -inline" performance when operating on Arrays is considerably worse than when directly operating on the data, we have a problem, as it likely to also impact other ranges. In short, I don't think the best solution is to add this special case to Array!T, but rather to figure out what exactly is wrong with Array!T and/or find() and fix the problem at its source. Could you post a short benchmark snippet explicitly showing the problem? Best, David "One" of the issue is the cost of repeatedly indexing Array, when internally it is nothing more than an array. Adding a special case "in" Array.Range allows bypassing the repeated indexing costs, but at the very least, should be implemented "in terms of" find itself, eg: Range searchForward(E)(E needle) if (isImplicitlyConvertible!(E, T)) { assert(_outer._data.refCountedStore.isInitialized); auto haystack = _outer._data._payload[_a .. _b]; haystack = haystack.find(needle); return Range(this._outer, _b - haystack.length, _b); }
Re: Array!T and find are slow
On Wednesday, 14 May 2014 at 15:42:13 UTC, Damian Day wrote: On Wednesday, 14 May 2014 at 14:54:57 UTC, David Nadlinger wrote: Could you post a short benchmark snippet explicitly showing the problem? Benchmark found here: http://dpaste.dzfl.pl/0058fc8341830 FYI, that implementation is wrong: Array.Range keeps `_a` and `_b`, which represents the "internal" bounds of the payload proper (and not "low" and "length"). You want something along the lines of: Range searchForward(E)(E needle) if (isImplicitlyConvertible!(E, T)) { assert(_data.refCountedStore.isInitialized); auto haystack = _data._payload[_a .. _b]; immutable len = _b - _a; for (size_t index = 0; index < len; ++index) { if (haystack[index] is needle) return Range(this, _b - len, _b); } return Range(this, _b, _b); } But even then, as I suggested above, while I think having searchForward could improve the situation, implementing it "in terms of" find would be better: This way, you'd still benefit from some of the highly optimized cases in find.
Re: Array!T and find are slow
On Wednesday, 14 May 2014 at 14:24:28 UTC, Damian Day wrote: I've found bench-marking my program that std.algorithm.find is very slow on Array!T, due to the fact it iterates on a range instead of a plain array. I've written some search functions, which are many times faster, is it worth making a pull request? http://dpaste.dzfl.pl/63b54aa27f35# BTW, this is a more "general" issue: Given a generic algorithm "std.foo", how can I write my own (better optimized) "object.foo", and make sure *that* is called instead? I initially filed the issue for "retro", while indeed mentioning that "find" was also open to the improvement: https://issues.dlang.org/show_bug.cgi?id=12583 This spawned the thread: http://forum.dlang.org/thread/op.xeuot6g2eav7ka@stevens-macbook-pro-2.local Unfortunately, nothing came of it.
Re: Array!T and find are slow
On Wednesday, 14 May 2014 at 20:29:52 UTC, David Nadlinger wrote: On Wednesday, 14 May 2014 at 17:36:35 UTC, monarch_dodra wrote: Adding a special case "in" Array.Range allows bypassing the repeated indexing costs, but at the very least, should be implemented "in terms of" find itself, eg: Shouldn't the extra indirection just vanish into thin air once opIndex or what have you is inlined? I don't see a conceptual reason for overhead in this case. Maybe. That said, currently, find doesn't use indexing for RA ranges. It simply uses a front/popFront for loop, so *that's* extra work. I just tried a RA/hasLength/hasSlicing case in find. It improves the situation by a factor of 2 on my machine (with dmd), but it is still somewhat slower than extracting the array directly. I'm usually reluctant to add extra code when the generic case works, but I feel we should make an exception for find. I don't know if the optimizer can optimize away the indirection entirely, when the code for front also does indexing, with bounds checking... Array comes with deterministic memory management, as well as non-invalidating range when relocation occurs. Extra overhead is to be expected. Of course, the compiler probably wouldn't be able to infer any of the memchr/… optimizations find does for the array case, but Damian's alternative version doesn't do any of that either. David The memchr optimization would only trigger for ubyte/byte and char (although a bug prevents Array from working with char https://issues.dlang.org/show_bug.cgi?id=8824) But more importantly, there are more flavors of find, such as with predicate, or range/range find. Having an implementation provide a thin wrapper might be acceptable. Reimplementation isn't.
Re: Array!T and find are slow
On Wednesday, 14 May 2014 at 21:20:06 UTC, Kapps wrote: That pull shows that the previous behaviour was to use enforce? Isn't this very expensive, particularly considering that enforce uses lazy non-scope arguments? Yes.
Re: Array!T and find are slow
On Thursday, 15 May 2014 at 04:37:16 UTC, Jonathan M Davis via Digitalmars-d-learn wrote: enforce(cond, "failure"); really should just translate to something close to if(!cond) throw new Exception("failure"); but it doesn't do anything close to that. And as long as it doesn't, enforce is of questionable value in any code that cares about efficiency. - Jonathan M Davis As a workaround, I'm sure we could specialize enforce without lazy for built-in types? BTW: Why *is* enforce lazy again? I don't really see it. I makes more sense for things like "collectException" I guess, but I don't see it for enforce.
Re: Array!T and find are slow
On Thursday, 15 May 2014 at 06:52:44 UTC, Jonathan M Davis via Digitalmars-d-learn wrote: On Thu, 15 May 2014 05:53:45 + monarch_dodra via Digitalmars-d-learn wrote: As a workaround, I'm sure we could specialize enforce without lazy for built-in types? No. I don't think that that would work. The problem is that you'd have to be able to overload between stuff like "error message" and format("error message: %s", foo), because you don't want the first one to be lazy, whereas you do want the second one to be lazy. Oh... right. It's the *second* parameter that's lazy. Arguably, the compiler should be able too "see" if the argument passed is a value or an expression though, and optimize accordingly.
Re: Why std.algorithm.sort can't be applied to char[]?
On Wednesday, 14 May 2014 at 09:01:23 UTC, John Colvin wrote: Why would anyone ever want to sort code-points? Why not? To remove duplicate characters? They might want to sort graphemes, but that's difficult to do in-place (needs O(n) memory, I think...). If out-of-place is good enough someStr.byGrapheme.array.sort(); The current "status quo" in D is that a dchar basically represents a character.
Re: Why std.algorithm.sort can't be applied to char[]?
On Thursday, 15 May 2014 at 13:26:45 UTC, Steven Schveighoffer wrote: On Wed, 14 May 2014 05:13:42 -0400, Jonathan M Davis via Digitalmars-d-learn wrote: On Wed, 14 May 2014 08:27:45 + monarch_dodra via Digitalmars-d-learn wrote: As a matter of fact, the built in "sort" property does it. void main() { char[] s = "éöeèûà".dup; s.sort; writeln(s); } //prints: eàèéöû I'm surprised. I thought that one of Bearophile's favorite complaints was that it didn't sort unicode properly (and hence one of the reasons that it should be removed). Regardless, I do think that it should be removed. I can't believe this worked. I want to say that it's a freak accident for that set of characters. Looking in druntime, I don't see where the special case is. -Steve Must be a hell of a freak accident ;) auto s = "é東öe京ûタèワà".dup; writeln(s.sort); => eàèéöûタワ京東 It's in rt/adi.d extern (C) char[] _adSortChar(char[] a) It's basically: string=>dstring=>sort=>dstring=>string. BTW, the built in reverse also works with char[], and so does std.algorithm.reverse (and it does it pretty cleverly too, might I say). As far as I'm concerned, if we *can* do it in n.log(n), and somebody provides the implementation, then there is no reason to not offer dchar sorting for char[]/wchar.
Re: [Rosettacode] Growable slices
On Thursday, 15 May 2014 at 09:00:13 UTC, bearophile wrote: This task asks for an basic implementation of the the Lempel-Ziv-Welch (LZW) compression/decompression algorithm. I am keeping two D versions, the first one is minimal, and the second is a little more optimized: http://rosettacode.org/wiki/LZW_compression#More_Refined_Version There are of course ways to implement a really efficient ZLW compressor in D, and such implementation could be added as third D entry if it manages to be not too much long, but for the first two versions keeping the code very short is more important. Despite the compressor in the second D entry is still not efficient at all, I have tried to make it not terrible regarding its efficiency, so I have defined a new kind of slice that can be extended, unlike the D slices, to avoid the string appends visible in the first D entry: struct Slice { size_t start, end; @property opSlice() const pure nothrow @safe @nogc { return original[start .. end]; } alias opSlice this; } Slice w; Tcomp[] result; foreach (immutable i; 0 .. original.length) { auto wc = Slice(w.start, w.end + 1); // Extend slice. if (wc in dict) { w = wc; } else { result ~= dict[w]; assert(dict.length < Tcomp.max); // Overflow guard. dict[wc] = cast(Tcomp)dict.length; w = Slice(i, i + 1); } } Is this showing a limit (problem) of D slices, or is this design better written in other ways? Bye, bearophile I don't think it shows a limit of "slices" in and out of itself, but rather the whole "range" concept, that conveniently encapsulates a start/end iteration scheme. The problem though is that, unlike iterators, these can only shrink, and never grow. Furthermore, it is usally hard to "split" a range into two parts, given a center iterator (especially for bidirectional-only ranges: EG: linked list). I think ranges/slices still provide more functionality and are worth it, but they do sacrifice *some* power: Growth and splitting. To be honest, what you are doing is essentially working with iterator pairs, disguised as indexes inside a "Slice" struct. Not that there's anything wrong with that, but that's my impression when looking at the code. Related: http://forum.dlang.org/thread/bhssgxfcscfbionhq...@forum.dlang.org#post-umxlhsfqmfjwydemfdeb:40forum.dlang.org http://forum.dlang.org/thread/gpsiwnslxtsyfolym...@forum.dlang.org#post-mailman.2149.1353648522.5162.digitalmars-d:40puremagic.com
Re: Why std.algorithm.sort can't be applied to char[]?
On Thursday, 15 May 2014 at 17:46:52 UTC, Steven Schveighoffer wrote: As far as I'm concerned, if we *can* do it in n.log(n), and somebody provides the implementation, then there is no reason to not offer dchar sorting for char[]/wchar. I think there is nothing wrong with requiring the steps to be explicit. We should not hide such bloat behind sort. -Steve Of course, but I meant if we could find an algoirthm O(1) (or O(log(N)) space overhead. If the only algorithm we are capable of providing just temporarily dstrings, then no.
Re: [Rosettacode] Growable slices
On Friday, 16 May 2014 at 15:20:04 UTC, bearophile wrote: Artur Skawina: Ugh. So how does it perform wrt the D version that I wrote for you last time? [1] I have done a benchmark with the various version (the first 3 are the ones on the Rosettacode site, and the #4 is yours): lzw1: 0.39 lzw2: 0.17 lzw3: 0.21 lzw4: 0.17 I think your comment was about an older version of the first entry, that is non meant to be fast, just short and simple. I think the second version is enough. Do you agree? The third version should be more efficient but for such small files it's slower than the second. Bye, bearophile Arguably, your code allocates a lot. To speed it up, arguably, you could store a global immutable string containing characters 0 to char.max + 1. This way, when you build your dictionary (each time you enter compress), you at least don't have to allocate the string, but rather, slice your global immutable. Ditto for the lines "w = [ch];", which allocates, you could instead do "w = gAllChars[ch .. ch + 1]". (or "dict[b] = [b]" etc...) Well, just a quick idea... I'll give it a shot (next week).
Re: [Rosettacode] Growable slices
On Friday, 16 May 2014 at 15:49:10 UTC, bearophile wrote: monarch_dodra: Arguably, your code allocates a lot. What version (1-2-3) do you mean? Any of the versions where you can see "[c]" or "[b]" where c/b is a char/byte
Re: Is it possible to assumeSafeAppend malloced memory?
On Monday, 19 May 2014 at 06:08:18 UTC, Ali Çehreli wrote: We know that most of the time memory is allocated more than the requested amount. Is there a way to take advantage of that extra trailing space? (And potentially the pages that come after that.) import core.memory; void main() { const count = 1; // I think there is extra capacity beyond the 'count' elements int* ptr = cast(int*)GC.malloc(count * int.sizeof); int[] arr = ptr[0 .. count]; assert(arr.capacity == 0); arr.assumeSafeAppend; assert(arr.capacity == 0);// still 0. :( } This issue puts std.array.array to a disadvantage compared to proper slices because array() involves the following call chain, the last of which does call GC.malloc: trustedAllocateArray uninitializedArray arrayAllocImpl As a result, iota(10).array.assumeSafeAppend ends up having 0 capacity. :( Ali Recently, a new function in druntime was added: "_d_newarrayU". This void allocates a new array *with* appendable information. We can hope it will be given a more formal and public interface, and it would then be useable by array and/or Appender, to produce slices that have appendable data.
Re: Is it possible to assumeSafeAppend malloced memory?
On Monday, 19 May 2014 at 13:55:00 UTC, Steven Schveighoffer wrote: On Monday, 19 May 2014 at 06:08:18 UTC, Ali Çehreli wrote: This issue puts std.array.array to a disadvantage compared to proper slices because array() involves the following call chain, the last of which does call GC.malloc: trustedAllocateArray uninitializedArray arrayAllocImpl This is a bug. arrayAllocImpl should alloc using the proper functions and flags. Well, Yes and no. The issue is that there is no interface available to achieve this, that wouldn't completely destroy what `array` is going for anyways. So it's more of a design issue than a bug proper. https://issues.dlang.org/show_bug.cgi?id=12444 https://github.com/D-Programming-Language/phobos/pull/2044 The only way I'd know (currently) to make it work, is with reserve+assumeSafeAppend. But the issue with that approach is that it's not pure (because of the whole purity with global GC side effects deal).
Re: Is it possible to assumeSafeAppend malloced memory?
On Monday, 19 May 2014 at 18:51:31 UTC, Dicebot wrote: If it still resorts to GC in this case, utility of such addition sounds questionable. It's not really an "addition" as much as it is a "necessary building block to make higher order GC functions work": For example, "dup" was recently made a druntime library implemented function, and as such, required that function to allocate, before building data onto it. Huh, will it also make possible to call `realloc` if capacity is exceeded? AFAIK, using the "GC.realloc" (or "GC.extent") function on it directly would not work. This may or may not be an issue with how "GC.realloc" is designed. The reason for this is because this functions are actually "extremelly" low level, and simply request GC memory, without knowing or caring about the APPENDABLE data. So while the calls could succeed, the result would not be useable. Currently, you could just use "reserve" or simply allocate again, to achieve almost the desired result. reserve+assumeSafeAppend would basically be a "void-extend" (as opposed to "size", which would be an "initialized extend"). At the end of the day though, it can all be done, but it's really about what you want to expose in "object.d".
Re: Question about @nogc
On Tuesday, 20 May 2014 at 12:25:11 UTC, Dominikus Dittes Scherkl wrote: Did I understand correct that a function can only be @nogc if also all functions that it calls are @nogc too (and of course it doesn't use the GC itself)? If so, should this be possible: string foo() { // use GC to allocate some string } bar @nogc { mixin(foo()); } Because, bar() didn't really call foo() but instead foo() is evaluated during compile time and it's result is now part of the code, right? Right. It's the same mechanics you'd get from pure/nothrow and @safe+@trusted
Re: byCodePoint for a range of chars
On Tuesday, 20 May 2014 at 17:59:09 UTC, John Colvin wrote: Given a range with element type char, what's the best way of iterating over it by code-point, without filling an array first? Related to this: What's the status of std.utf and std.encoding? The comments in std.encoding say that some functions supersede their std.utf counterparts. FWI, Walter just wrote "byDchar", that does what you want: https://github.com/D-Programming-Language/phobos/pull/2043 It's about to be merged.
Re: byCodePoint for a range of chars
On Tuesday, 20 May 2014 at 18:06:09 UTC, Justin Whear wrote: Foreach on narrow strings automatically decodes, so it's as simple as: // assume UTF-8 encoded char[] myData = ... foreach (dchar codePoint; myData) ... I think the point of his question is if you have an actual non-array range of chars, in which case foreach does NOT decode. It simply iterates.
Re: Question about @nogc
On Tuesday, 20 May 2014 at 21:04:37 UTC, anonymous wrote: On Tuesday, 20 May 2014 at 20:15:09 UTC, Dominikus Dittes Scherkl wrote: /// create a fixed size array with the given name and with *max* entries max + 1 entries /// of immutable values of the same type as the return value of the /// given function. /// it contains the values of that function in the range [0..max]. string makeLookupTable(alias fn, uint max=255)(string name) pure @safe if(is(typeof(fn(max { string table = "immutable " ~ to!string(typeof(fn(max))) ~ "[" ~ to!string(max+1) ~ "] " ~ name ~"= [ "; foreach(i; 0..max) table ~= to!string(fn(i) ~ ", "; return table ~ to!string(fn(max) ~" ]"; } Couldn't resist purging that of the string fiddling: ... enum ReturnType!fn[length] lookupTable = [elements]; Depending on what the usecase is, you might want to change that to static immutable instead: static immutable ReturnType!fn[length] lookupTable = [elements]; Remember that when using an enum, the compiler will create a *new* variable on every use. While the compiler can sometimes avoid actually allocating, it may also insert some object code bloat to do so.
Re: How to get struct's members ?
On Friday, 23 May 2014 at 01:17:18 UTC, bioinfornatics wrote: Dear, I would like to get struct's members and zip them with an action as struct A { int a; int b; } std.range.zip( __traits( allmembers, A ), [(x) => x == 0, (y) => y > 3] ); like this i could apply an action to each field. I tried this: http://dpaste.dzfl.pl/747799ffa64e but: tuple get by allmembers is not an input rage then i can't to use zip allmembers return both fiels and method while i would like only fields thanks tupleof will do what you need (mostly). However, I don't think there will be any way to (generically) run-time zip on the members, due to probably type mismatch, and memory layout. In any case, nothing trivial, AFAIK.
Re: How to get struct's members ?
On Friday, 23 May 2014 at 08:20:05 UTC, Philippe Sigaud via Digitalmars-d-learn wrote: On Fri, May 23, 2014 at 8:44 AM, monarch_dodra via Digitalmars-d-learn wrote: On Friday, 23 May 2014 at 01:17:18 UTC, bioinfornatics wrote: I would like to get struct's members and zip them with an action tupleof will do what you need (mostly). However, I don't think there will be any way to (generically) run-time zip on the members, due to probably type mismatch, and memory layout. In any case, nothing trivial, AFAIK. You can define a map-like (or zip-like) template to act on tuples as if they were ranges, but the resulting type will still be a tuple: in general, the members and the delegates associated with them will all have a different type. Bioinfornatics, if you know your struct members are all of the same type, you can 'cast' the tuple as an array by wrapping it in square brackets like this: [ myStruct.tupleof ] and then use the usual range algorithms. One issue with this is that it will allocate a copy of all the elements. This may be fine if the elements are meant for a "read-only" operation. But it won't solve the issue if there are any mutating operations. Just saying.
Re: How to handle try-catch blocks, nothrow and logfiles
On Saturday, 24 May 2014 at 17:09:24 UTC, Tim wrote: Imagine I've an application where I want log all thrown exceptions. Arguably, that's not something you'd want to do. In a "normal" application, exceptions get thrown around, and it is completely normal. In particular, the *thrower* has no way to know its context, and whether or not the situation it has encountered is "catastrophic exception" or "completely normal". Only the "catcher" can know. 2) When I want create an application where all methods are defined as >nothrow< - how can I realize that? Writing to a log-file is already throwable. Yes, I can catch the exception and write the same to the command line but that's also unsafe... are there any nothrow-function to write a file or something to the command line? It's a bit sad when I want log an exception and I'm unable to write the log entry because something happened. So how can make sure that I log all exceptions? Is that even possible? Well, you seem to be mixing the notion of "nothrow" and "safe", which are orthogonal concepts. Most logging frameworks "gag" their exceptions, which makes them nothrow. This doesn't mean that exceptional things can't happen: It only means the exceptions will not "escape" from the call.
Re: What are the best std algo for testing a range implementation ?
On Tuesday, 27 May 2014 at 10:50:54 UTC, BicMedium wrote: Let's say I have a set of containers, using a D-unfriendly-semantic. They rather use a kind of ADA vocabulary (according to https://en.wikipedia.org/wiki/Deque). I want to make them "range-aware". If the input/output ranges are easy to implement(so it's just reading/writing an element, keeping an index for the writer and another for the reader, and reseting it, isn't it ? So if (isInputRange!MyCont && isOutputRange!MyCont) then it's a "Deque", right ?). The bidirectionnal ranges or the forward ranges become more difficult to interpret with the idioms I use(Insert,Add,Remove)...Is this a kind of 3rd plane ("time": "return to previous state", "make a backup": copy/roll-back - undo/redo ?) Just keep in mind that a container is not a range. A container is an object that can hold items, and you can add and remove items from said object. The Range is a way to iterate your container. For example, a range definitely does NOT make insertion, removals or duplactes of your items. You can "save" a range, but that's NOT the same thing as making a duplicate of your container that you can roll back. I'd suggest you take a look at std.container.array to see what I'm talking about. Could you recommend me the algos from std.algo to test efficiently my implementations ? (example, if you want to be sure that the input ranges work then you'd use this...if you want to be sure that output ranges work then you'd use that ...Some kind of "reference" unit tests ?). At the present time, each time I try one I get rejected by the template constraints... If the algos are turning you down, then you must have missed something. Check that: alias Range = YourRangeTypeHere; static assert(isInputRange!Range); static assert(isForwardRange!Range); static assert(isBidirectionalRange!Range); static assert(hasLength!Range); static assert(isRandomAccessRange!Range); static assert(hasSlicing!Range); At the *very least*, the first 3 should pass for a deque. The 3 others depend on what primitives you want to offer.
Re: What are the best std algo for testing a range implementation ?
On Tuesday, 27 May 2014 at 12:18:15 UTC, BicMedium wrote: I mean that those tests are just like testing an interface...). If your interface isn't complete, than it is irrelevant what your implementations are, since the algorithms can't use your ranges anyways. BTW the 2nd and the 3rd assertions are exactly what fails when I try to test an algo (isInputRange!Range or isOutputRange!Range pass but has the test doesn't know about the implementation I can't know If it's really working... Probably you are missing `save`, or you implemented it as a non-property function (though arguably, it shouldn't be a property, but that's another issue).
Re: RandomAccessRange / Mobile Elements
On Tuesday, 27 May 2014 at 13:04:50 UTC, Johann wrote: Hello, I read in std.range that given a random access range r , r.opIndex(n) should return a reference to the nth element. Is there a qualifier for a "read only" random access range? If not, why? The documentation is a bit wrong. It doesn't actually have to be a reference. You may return by value if you want, which is a "form" of read-only access. If you want to return actual const references or elements, you may do so if you so wish, but this would done via the range's type itself, rather than the function. Eg, you'd have "Range" and "ConstRange". It's currently a big subject of discussion. I also don't really get the point of "Mobile Elements", how is "destructively reading" related to mobility If you move something from A to B, then whatever was at A is not there anymore. How is that not destructively reading? and what is it good for? Arguably, performance. If you don't need to re-use your elements at a future date, then instead of creating a duplicate copy via postblit (which could be arbitrarily expensive), we simply move the data, which is much cheaper. Thanks. You're welcome :)
Re: What are the best std algo for testing a range implementation ?
On Tuesday, 27 May 2014 at 16:49:42 UTC, BicMedium wrote: But there could be a templated-unittest for those kind of things...Ranges are relatively straightforward in to use, but when you want to implement one, it's another thing...So it's just about indexes ? And a kind of State machine for indexes (push/pop) ? We can't wright a generic unittest to make sure that a range "works". Indeed, depending on *what* your range iterates, the test would be different. You just have to test that yourself. I hardly get how to make my easy containers range-aware. but I want to, because of std.algo. The easiest way is to give your container the "Range opSlice()" function, where Range is the range you defined to iterate on your container. See std.container.array.
Re: Cost of .dup vs. instantiation
On Wednesday, 28 May 2014 at 14:36:25 UTC, Chris wrote: I use Appender to fill an array. The Appender is a class variable and is not instantiated with each function call to save instantiation. However, the return value or the function must be dup'ed, like so: Appender!(MyType[]) append; public auto doSomething() { scope (exit) { // clear append } // ... do something append ~= item; return (append.data).dup } My question is whether I save anything with Appender as a class variable here. I have to .dup the return value (+ clear the Appender). If I had a new Appender with each function call, it might be just as good. public auto doSomething() { Appender!(MyType[]) append; // return append.data. } Right or wrong? You might save a little because you avoid the cost of "growing" your appender repeatedly: Once the appender has come to "maturity", it will very likely stop growing. At that point, you only pay for *1* allocation per call to doSomething. Further advantages include: - dup has "APPENDABLE" info (whereas appender.data does not). - less wasted memory: dup uses no more memory than it has to, whereas Appender may over-allocate, depending on how you fill it. The "downside" to your approach is that you keep a handle on a buffer that can grow, but never shrink. If a at a certain point, you have to process some particularly large input, then you'll consume excessive amounts of memory.
Re: std.algorithm range violation
On Wednesday, 28 May 2014 at 11:40:05 UTC, Wanderer wrote: Sorry about typo, I meant providor_symbol_map.sort!((x,y)=>{x.value.length>y.value.length}) above. providor_symbol_map is an Associative Array, so you can't sort that. *Usually*, you want to do what the OP did, which is to get the keys, and sort them, but leave the AA unchanged. EG: Val[Key] myAA; Key[] mySortedKeys = myAA.keys.sort!((x, y)=> compare(myAA[x], myAA[y]))() //Print values in incremented order: foreach(key; mySortedKeys) writefln("%s: %s", key, myAA[key]);
Re: std.algorithm range violation
On Wednesday, 28 May 2014 at 17:39:15 UTC, monarch_dodra wrote: On Wednesday, 28 May 2014 at 11:40:05 UTC, Wanderer wrote: Sorry about typo, I meant providor_symbol_map.sort!((x,y)=>{x.value.length>y.value.length}) above. providor_symbol_map is an Associative Array, so you can't sort that. *Usually*, you want to do what the OP did, which is to get the keys, and sort them, but leave the AA unchanged. EG: Val[Key] myAA; Key[] mySortedKeys = myAA.keys.sort!((x, y)=> compare(myAA[x], myAA[y]))() //Print values in incremented order: foreach(key; mySortedKeys) writefln("%s: %s", key, myAA[key]); I case this was not clear "compare" is an function you should replace with your own. It should simply define strict ordering of x and y. "<" is one such function.
Re: @safe @nogc memory allocation
On Wednesday, 28 May 2014 at 19:43:53 UTC, Nordlöw wrote: I would like my radix sort function radixSortImpl() at https://github.com/nordlow/justd/blob/master/intsort.d to not use the GC. However, when I tag with @nogc I get the error: intsort.d(195,47): Error: @nogc function 'isort.radixSortImpl!(byte[], "a", false).radixSortImpl' cannot call non-@nogc function 'std.array.uninitializedArray!(byte[], immutable(ulong)).uninitializedArray' Is there an alternative to std.array: uninitializedArray Elem[] y = uninitializedArray!(Elem[])(n); that neither use the GC and nor preinitialize the data? malloc? There's no wrapper around it though, like there is for uninitializedArray. Keep in mind though that currently, you have to choose either of "pure" (GC) or "nogc" (malloc) if you need dynamic allocation :/ Could the recent DMD pull optimization to scope here https://github.com/D-Programming-Language/dmd/commit/abc7033bf9cf7f7224a47e45096efc48a21b5ab8 be used? /Per I don't think scope can be used to create a dynamic array on the stack. I think it requires the object's type be statically known. I could be wrong though. If you know "n" has a max size, you could you create a fixed size array, or attempt a "alloca" array?
Re: @safe @nogc memory allocation
On Wednesday, 28 May 2014 at 20:00:17 UTC, safety0ff wrote: I think malloc isn't @safe and alloca doesn't work if your function can throw. Yeah, uninitializedArray is also *only* trusted if the type in question has no indirections. I've heard of several bugs with alloca, but I don't know the exact list.
Re: Cost of .dup vs. instantiation
On Thursday, 29 May 2014 at 08:49:10 UTC, Chris wrote: monarch_dodra: Hm. This last point might be an issue. If I process a large input (text in this case) then I might run into trouble with "append" as a class variable. I also had a weird bug, because I didn't clear the memory for overwrite. You can always implement an "upper bound" approach, where if your input data becomes larger than a certain size, you return the data directly, and reset your appender. EG: Appender!(MyType[]) append; public auto doSomething() { scope (failure) { append.clear; } // ... do something append ~= item; MyType[] ret; if (append.data.length < 10_000) { ret = append.data).dup; append.clear; //clears buffer, keeps memory. } else { ret = append.data; append = appender!(MyType[])(); //jettison old appender data. } return ret; }
Re: enums
On Friday, 30 May 2014 at 15:30:15 UTC, Russel Winder via Digitalmars-d-learn wrote: I think I have no idea what D enums are about. Bearophile's example of some code in an email on another thread uses: enum double p0 = 0.0045; Now I would have written: immutable double p0 = 0.0045; or at the very worst: const double p0 = 0.0045; For me, enum means create an enumerated type. Thus "enum double" to define a single value is just a contradiction. Enlightenment required… The keyword "enum" stems from the enum hack in C++, where you use: enum {foo = 100}; //Or similar As a way to declare a manifest constant known at compile time. D simply "hijacked" the "enum" keyword to mean "manifest constant that is known at compile time". Compared to an immutable instance: * The immutable instance creates an actual reference-able object in your binary. The enum will not exist outside of the compilation (think of it as a higher order macro) * immutable represents a value, which *may* be initialized at runtime. In any case, more often than not (I have observed), the compiler will refuse to use the immutable's value as compile-time known, and it won't be useable as a template parameter, or static if constraint.
Re: Different random shuffles generated when compiled with gdc than with dmd
On Friday, 30 May 2014 at 13:39:18 UTC, Andrew Brown wrote: Hi there, The following code: void main(){ import std.array : array; import std.stdio : writeln; import std.random : rndGen, randomShuffle; import std.range : iota; rndGen.seed(12); int[] temp = iota(10).array; randomShuffle(temp); writeln(temp); } writes [1, 8, 4, 2, 0, 7, 5, 6, 9, 3] if it's compiled with dmd, but [1, 7, 4, 6, 2, 9, 5, 0, 3, 8] with gdc. ... Andrew Are you sure you are compiling with the same version of dmd and gdc? Fixes were made to the rand.d library in the latest release, which could explain the difference you are observing.
Re: Different random shuffles generated when compiled with gdc than with dmd
On Friday, 30 May 2014 at 18:41:55 UTC, Joseph Rushton Wakeling via Digitalmars-d-learn wrote: On 30/05/14 18:13, monarch_dodra via Digitalmars-d-learn wrote: Are you sure you are compiling with the same version of dmd and gdc? Fixes were made to the rand.d library in the latest release, which could explain the difference you are observing. Which fixes are you thinking of here ... ? I don't recall anything that ought to alter the behaviour of the standard random number generator. Didn't you make changes to how and when the global PRNG is popped and accessed in randomShuffle? I figured it *could* be an explanation.
Re: enums
On Saturday, 31 May 2014 at 21:21:59 UTC, Paul D Anderson wrote: 'enum' as a manifest constant keyword has been an unpopular decision from its introduction. "Everybody" agrees that it should be changed. Everybody but Walter I find enum makes sense.
Re: How to sort a 2D array by column
On Saturday, 7 June 2014 at 19:06:10 UTC, katuday wrote: the_table.sort; // I believe this sort uses all the columns inside the_row. What I want is use specific column(s) Supposing you use the *function* "std.algorithm.sort", then that is going to sort you rows according to the (default) predicate "<". In this case, "<" means lexicographical comparison for arrays. EG: compares the first element, then the second, then the third, until 2 are different. I don't have your input, but here is an example program: import std.stdio, std.algorithm, std.random; // void main() { int[][] arr = new int[][](10, 10); foreach(i; 0 .. 10) foreach(j; 0 .. 10) { arr[i][j] = rndGen().front % 5; rndGen().popFront(); } writefln("%(%s\n%)", arr.sort()); //Note the "()": Very important. } // [0, 1, 0, 0, 0, 0, 2, 3, 1, 1] [0, 4, 4, 1, 2, 3, 4, 2, 1, 0] As you can see here, this was ordered by looking up to 5 elements deep. If you need something more customize, you can do it by specifying your own function. For example, according to each row's Euclidean norm: // bool compare(int[] lhs, int[] rhs) { auto a = reduce!"a += b^2"(0, lhs); auto b = reduce!"a += b^2"(0, rhs); return a < b; } void main() { int[][] arr = new int[][](10, 4); foreach(i; 0 .. 10) foreach(j; 0 .. 4) { arr[i][j] = rndGen().front % 9 - 4; rndGen().popFront(); } writefln("%(%2s\n%)", arr.sort!compare); } // [-2, -3, -1, 3] [ 4, -2, -2, -2] [-2, 0, 2, -4] [ 3, -2, -4, 1] [ 3, -2, 2, 3] [-2, 3, 3, 0] [ 1, 2, 0, -2] [ 4, 2, -1, 0] [ 2, 1, 1, 3] [ 3, 3, 3, 4] // In the above examples, I used numbers, but the language really doesn't care, as long as your elements have strict total ordering according to the predicate you have used.
Re: How to sort a 2D array by column
On Saturday, 7 June 2014 at 20:47:31 UTC, katuday wrote: On Saturday, 7 June 2014 at 19:18:34 UTC, Chris Cain wrote: On Saturday, 7 June 2014 at 19:14:01 UTC, Chris Cain wrote: This is my attemot to create a compare object. But I don't know how to use it together with .sort member function Don't use the .sort property. Use std.algorithm.sort, which has a "less" predicate (that should return a bool). http://dlang.org/phobos/std_algorithm.html#sort Also note that the examples use a string to define the predicate, but it accepts functions as well. Such as: bool myCompareFunc(AType lhs, AType rhs) { return lhs.blah < rhs.blah; } //... AType[] arr; //... arr.sort!myCompareFunc(); I need an example if you don't mind. My sort function requires columns numbers supplied at run-time This is how I defined my sort function bool compareRow(int[] columns, ref const Row lhs, ref const Row rhs) { bool ret = false; for (auto i = 0; i < columns.length; ++i) { const auto currentColumn = columns[i]; if (lhs[currentColumn] < rhs[currentColumn] ) ret = true; if (rhs[currentColumn] < lhs[currentColumn] ) ret = false; } return ret; } That function don't make no sense (to me): It'll just return the result of the last iteration. It *looks* like you are trying to do a lexicographical comparison? You should just replace those "ret = XXX" with straight up "return XXX". The last "return ret" should be "return false" (I think) Calling sort like this does not compile sort!(compareRow)(sort_key,the_table); You need to create a delegate that binds your sort key to have predicate that accepts exactly 2 arguments. A lambda will fill that role. sort!((lhs, rhs)=>compareRow(sort_key, a, b))(the_table); or (not tested) use std.functional's curry: sort!(curry!(compareRow, sort_key))(the_table);
Re: Conversion string->int
On Saturday, 7 June 2014 at 20:53:03 UTC, Paul wrote: I can not understand, why this code works: char s[2] = ['0', 'A']; string ss = to!string(s); writeln(parse!uint(ss, 16)); but this can deduces template: char s[2] = ['0', 'A']; writeln(parse!uint(to!string(s), 16)); What's the reason? And what is the right way to parse char[2]->int with radix? parse takes an lvalue to a range. char[2] is a static array, and is not a range. You need to store an actual "char[]" (or string) in a variable to call parse. So "ss" will work, "to!string(s)" will not.
Re: array as parameter
On Saturday, 7 June 2014 at 20:56:14 UTC, Paul wrote: Dynamic array is really reference. Right? But why modification of parameter in this case does not work: void some_func(string[] s) { s ~= "xxx"; s ~= "yyy"; } but this works: void some_fun(ref string[] s) { s ~= "xxx"; s ~= "yyy"; } In the 1st case s is reference too, is not it? It's a value type that holds a reference to data. If you modify the *actual* slice, rather than the referenced items, then you need to pass by ref.
Re: Permutation Sort Algorithm Very Slow
On Saturday, 7 June 2014 at 22:01:25 UTC, Ali GOREN wrote: Thank you. I can not resolve it in quicker time, right? Depends what exactly you want to achieve. This will achieve the same result in a fraction of the time. void main() { auto data = [2, 7, 4, 3, 5, 1, 0, 9, 8, 6, -1]; sort(data); data.writeln; } But it's not "permutation sort". Honestly, I've never *heard* of "permutation sort". In any case, it's one of the worst sorts I've ever heard of. If you want to use a bad algorithm, you could also go for bogosort: void main() { auto data = [2, 7, 4, 3, 5, 1, 0, 9, 8, 6, -1]; while (!isSorted(data)) randomShuffle(data); data.writeln; }
Re: Interesting bug with std.random.uniform and dchar
On Sunday, 8 June 2014 at 08:54:30 UTC, Joseph Rushton Wakeling via Digitalmars-d-learn wrote: I think it should suffice to forbid uniform!T from accepting dchar parameters and to tweak the integral-type uniform()'s internal check to avoid calling that specialization with dchar. Thoughts ... ? Thanks & best wishes, -- Joe Why would we ban uniform!T from accepting dchar? I see no reason for that. Let's just fix the bug by tweaking the internal check.
Re: Interesting bug with std.random.uniform and dchar
On Sunday, 8 June 2014 at 13:55:48 UTC, H. S. Teoh via Digitalmars-d-learn wrote: On Sun, Jun 08, 2014 at 11:17:41AM +0200, Joseph Rushton Wakeling via Digitalmars-d-learn wrote: On 08/06/14 11:02, monarch_dodra via Digitalmars-d-learn wrote: >Why would we ban uniform!T from accepting dchar? I see no >reason for that. > >Let's just fix the bug by tweaking the internal check. Yea, I came to the same conclusion while working on it. :-) The solution I have is (i) in uniform!"[]" check that !is(ResultType == dchar) before checking the condition for calling uniform!ResultType, and (ii) inside uniform!T, place static if (is(T == dchar)) { return uniform!"[]"(T.min, T.max, rng); } Doesn't wchar need to have a similar specialization too? Aren't some values of wchar invalid as well? T Arguably, the issue is the difference between "invalid" and downright "illegal" values. The thing about dchar is that while it *can* have values higher than dchar max, it's (AFAIK) illegal to have them, and the compiler (if it can) will flag you for it: dchar c1 = 0x_D800; //Invalid, but fine. dchar c2 = 0x_; //Illegal, nope.
Re: scope exit in mixin template
On Sunday, 8 June 2014 at 18:28:25 UTC, Byron wrote: Can we not use scope(..) in a mixin template? struct bar {} bar* c_make() { return new bar(); } void c_free(bar* b) { b = null; } mixin template Foo() { auto b = c_make; scope(exit) if(b) c_free(b); } void main() { mixin Foo; } I get Error: Declaration expected, not '(' -Byron Mixin templates can only insert declarations, not arbitrary code. When it sees "scope", it's expecting it to be the attribute, not the declaration.
Re: scope exit in mixin template
On Sunday, 8 June 2014 at 18:48:03 UTC, monarch_dodra wrote: Mixin templates can only insert declarations, not arbitrary code. When it sees "scope", it's expecting it to be the attribute, not the declaration. To add to that, if you want to mixin arbitrary code, then you can use a string mixin: template declare_bar(string var_name) { enum declare_bar = "auto " ~ var_name ~ " = c_make();" ~ "scope(exit) if(" ~ var_name ~ ") c_free(" ~ var_name ~ ");" } void main() { mixin(declar_var!"b") } For example. That said, given your example, simply using an RAII wrapper *could* be superior (depends on your actual usecase).
Re: scope exit in mixin template
On Sunday, 8 June 2014 at 18:28:25 UTC, Byron wrote: void c_free(bar* b) { b = null; } Heads up: This code does nothing. You are passing the pointer by value, so "b = null;" will have no effect at the end of the call. Use pass by ref: void c_free(ref bar* b) { b = null; }
Re: splitter for strings
On Monday, 9 June 2014 at 10:23:16 UTC, Chris wrote: Ok, thanks. I'll keep that in mind for the next version. Seems to me to also work with 2.065 and 2.064.
Re: splitter for strings
On Monday, 9 June 2014 at 11:04:12 UTC, Chris wrote: From the library reference: assert(equal(splitter("hello world", ' '), [ "hello", "", "world" ])); and "If a range with one separator is given, the result is a range with two empty elements." My problem was that if I have input like auto word = "bla-"; it will return parts.data.length == 2, so I would have to check parts.data[1] != "". This is too awkward. I just want the parts of the word, i.e. length == 2 // grab [0] grab [1] length == 1 // grab [0] (no second part, as in "bla-") length > 2 // do something else You can just pipe in an extra "filter!(a=>!a.empty)", and it'll do what you want: put(parts, w.splitter('-').filter!(a=>!a.empty)()); The rational for this behavior, is that it preserves the "total amount of information" from your input. EG: assert(equal(myString.spliter(sep).join(sep), myString)); If the empty tokens were all stripped out, that wouldn't work, you'd have lost information about how many separators there actually were, and where they were.
Re: splitter for strings
On Monday, 9 June 2014 at 11:40:24 UTC, Chris wrote: On Monday, 9 June 2014 at 11:16:18 UTC, monarch_dodra wrote: On Monday, 9 June 2014 at 11:04:12 UTC, Chris wrote: From the library reference: assert(equal(splitter("hello world", ' '), [ "hello", "", "world" ])); and "If a range with one separator is given, the result is a range with two empty elements." My problem was that if I have input like auto word = "bla-"; it will return parts.data.length == 2, so I would have to check parts.data[1] != "". This is too awkward. I just want the parts of the word, i.e. length == 2 // grab [0] grab [1] length == 1 // grab [0] (no second part, as in "bla-") length > 2 // do something else You can just pipe in an extra "filter!(a=>!a.empty)", and it'll do what you want: put(parts, w.splitter('-').filter!(a=>!a.empty)()); The rational for this behavior, is that it preserves the "total amount of information" from your input. EG: assert(equal(myString.spliter(sep).join(sep), myString)); If the empty tokens were all stripped out, that wouldn't work, you'd have lost information about how many separators there actually were, and where they were. I see, I've already popped in a filter. I only wonder how much of a performance loss that is. Probably negligible. Arguably, none, since someone has to do the check anyways. If it's not done "outside" of splitter, it has to be done inside...
Re: splitter for strings
On Monday, 9 June 2014 at 14:21:21 UTC, Steven Schveighoffer wrote: Just looked at std.string for a strip function that allows custom character strippage, but apparently not there. The above is quite awkward. -Steve It's in algorithm, because it's more generic than just strings.
Re: splitter for strings
On Monday, 9 June 2014 at 15:19:05 UTC, Chris wrote: On Monday, 9 June 2014 at 14:47:45 UTC, Steven Schveighoffer wrote: On Mon, 09 Jun 2014 10:39:39 -0400, Chris wrote: Atm, I have auto parts = appender!(string[]); w.splitter('-').filter!(a => !a.empty).copy(parts); Which looks more elegant and gives me what I want. IMO, the module that handles the splitting of hyphenated words should be able to deal with cases like "blah-" without the input being prepared in a certain way. It's not mishandled. It's handled exactly as I would have expected. If "blah-" and "blah" result in the same thing, then how do you know the difference? Stripping any possible leading or trailing hyphens is much more efficient than checking every single word to see if it's empty. However, if you have an instance of "--", your solution will remove the extra empty string, whereas mine does not. Not sure if that's important. -Steve It is important. "blah--" should come out as "blah". The logic is along the following lines: if (canFind(w, "-")) { auto parts = appender!(string[]); w.splitter('-').filter!(a => !a.empty).copy(parts); if (parts.data.length == 1) { // false alarm. Trailing hyphen } } The more common case is that it's not a trailing hyphen. std.string.strip() only works for whitespaces. Would be nice to have something like that for random characters. strip(s, '-') or strip(s, ['-', '+', '@']) http://dlang.org/phobos/std_algorithm.html#strip w = w.strip('-'); if (canFind(w, "-")) { ...
Re: splitter for strings
On Monday, 9 June 2014 at 15:54:29 UTC, Steven Schveighoffer wrote: On Mon, 09 Jun 2014 11:49:29 -0400, monarch_dodra wrote: On Monday, 9 June 2014 at 14:21:21 UTC, Steven Schveighoffer wrote: Just looked at std.string for a strip function that allows custom character strippage, but apparently not there. The above is quite awkward. -Steve It's in algorithm, because it's more generic than just strings. Ugh.. This makes things difficult. If I want to work with strings, I import std.string. I understand that the algorithm is applicable to all types, but this makes for some awkward coding. What if you wanted to use both? Surely we can come up with a better solution than this. -Steve There's 2 different issues: The first, is that "split(string)" was pre-existing in std.string, and *then* split was introduced in algorithm. Where ideally (?) everything would have been placed in the same module, we true to avoid moving things around now. The second thing is that "split" without any predicate/item can only make sense for strings, but not for generic ranges. For what it's worth, I find it makes sense.
Re: hijacking override from template mixin
On Monday, 9 June 2014 at 15:54:21 UTC, Ivan Kazmenko wrote: I'd expect a "multiple overrides of same function" error, much like if I just paste the mixin code by hand. Is that a bug or working by design? In the latter case, please explain the reasoning. AFAIK, the rationale is that *should* a colision happen, the local symbol shadows the mixed-in symbol. Doing this avoid breaking your code just because someone added an extra member in their mixin, which happened to conflict with one of yours. The idea is that you can workaround the issue by "naming" your mixin templates. Then, when you want to access members of the mixin template, you *know* it'll always work, regardless of what else may have been declared in your class. That said, for something like virrtual functions, things get a bit trickier, since your *aren't* supposed to call them explicitly... I don't know if bug, or just surprising behavior.
Re: splitter for strings
On Monday, 9 June 2014 at 17:57:24 UTC, Steven Schveighoffer wrote: I think we are confusing things here, I was talking about strip :) strip and split are actually both pretty much in the same boat actually in regards to that, so just 's/split/strip/g', and the same answer will apply. "split" (and "splitter") actually have it a bit more complicated, because historically, if you imported both string and algorithm, then "split(myString)" will create an ambiguous call. The issue is that you can't do selective imports when you already have a local object with the same name, so algorithm had: auto split(String)(String myString) { return std.string.split(myString); } rather than public import std.string : split; I tried to "fix" the issue by removing "split(String)" from algorithm, but that created some breakage. So Andrei just came down and put *everything* in algorithm, and added an "public import std.algorithm : split" in std.string. This works, but it does mean that: 1. string unconditionally pulls algorithm. 2. You can do things like: std.string.split([1, 2, 3], 2); IMO, the "strip" solution is better :/ If we could split up std.algorithm into individual modules, that would probably help. -Steve Yes.
Re: splitter for strings
On Monday, 9 June 2014 at 19:47:29 UTC, Chris wrote: Uh, I see, I misread the signature of std.string.strip(). So that's one option now, to strip all trailing hyphens with std.string.strip(). Well, I'll give it a shot tomorrow. No, you read the documentation of std.*STRING*.strip correctly. I'm suggesting you use the one from std.*ALGORITHM*. The signatures are mutually exclusive, so you don't need to qualify them.
Re: splitter for strings
On Monday, 9 June 2014 at 19:54:08 UTC, Chris wrote: I think it makes sense to put any generic range based algorithms (split and so forth) into std.algorithm. It's always my first port of call, when I have a range. However, that you can do std.string.split([1, 2, 3], 2); is not exactly a desirable situation. Right, but "split(hello world)" *is* string specific. It makes sense for strings only. It doens't make sense to write "split([1, 2, 3])", which is why I'm unsatisfied with the current situation.
Re: D aliases vs. C typedefs
On Tuesday, 10 June 2014 at 20:33:03 UTC, Ali Çehreli wrote: I think they are actually legal: This is D's support of C-style array declaration acting the same in alias declaration: Ali C-style array declaration has got to be one of C's *worst* abominations. There's no real *technical* rationale for it either. I am ***INCREDIBLY*** glad D's stance is simply "depth first left to right". It *supports* C style, but unless you are copy pasting some C code, you'd have to be mad in your head to actually ever use it. Honestly, try to declare: *A two element array of pointers to int *A pointer to a two element array of ints Tip: the solutions are in this set: int *arr1[2]; int (*arr2)[2]; int *(arr3[2]); Also, the syntax is *so* horrible, the syntax is actually deprecated in D. And that's saying a lot, when you know how much Walter hates breaking code...
Re: Splitting Ranges using Lambda Predicates
On Tuesday, 10 June 2014 at 21:11:17 UTC, Nordlöw wrote: 1. someName => SomeName My example is dumb and incorrect. I actually want this to do the following 2. "_someGreatVariableName" => "Some Great Varible Name" The current splitter works on the notion of splitter "tokens", eg, it splits when it find an element or range that corresponds to the passed value/pred. What exactly are you requesting though? - Split on the "edge" lowercase to uppercase? - Split on uppercase but keep the uppercase element? Either way, your example should look like this: "SomeGreatVariableName" => ["Some", "Great", "Variable", "Name"] Since you are splitting up your range into subranges. And also either way, AFAIK, yeah, we don't have any splitter that does that. We are also missing the version that takes both a range an predicate, which would allow things like: "This Cool thing is COOL!!!".split((a, b)=>a == b.toLower())("cool") => ["This ", " thing is ", "!!!"] Looks like you'll have to roll your own :/
Re: Splitting Ranges using Lambda Predicates
On Tuesday, 10 June 2014 at 21:26:50 UTC, monarch_dodr What exactly are you requesting though? - Split on the "edge" lowercase to uppercase? - Split on uppercase but keep the uppercase element? Thinking about this more: Do you *actually* have two different predicates, or are they mutually exclusive? EG: predicate "isUpper", and split on a false->true? Either way, it shouldn't be too hard to implement. Base it off "splitter!pred", which is actually quite trivial. AFAIK, your requirements could even make it simpler, since you don't need to "skip" the splitter element (which, for strings, can actually be tricky business...). You'd just have to use 2 calls to find though, for "both your predicates" or for "not predicate then predicate".
Re: Splitting Ranges using Lambda Predicates
On Tuesday, 10 June 2014 at 22:31:37 UTC, Nordlöw wrote: Either way, it shouldn't be too hard to implement. Base it off "splitter!pred", which is actually quite trivial. AFAIK, your What do you mean by basing it off splitter!pred - should I start with some existing splitter algorithm in Phobos or start from scratch? Thx. I meant mostly copy pasting it, and modifying it to your needs. For example, I adapted it into this. For simplicity, I stripped infinite and forward only range support. The only functions I actually modified were "findTerminator", to actually find according to what I want, and popFront. // auto slicer(alias isTerminator, Range)(Range input) if (((isRandomAccessRange!Range && hasSlicing!Range) || isSomeString!Range) && is(typeof(unaryFun!isTerminator(input.front { return SlicerResult!(unaryFun!isTerminator, Range)(input); } private struct SlicerResult(alias isTerminator, Range) { alias notTerminator = not!isTerminator; private Range _input; private size_t _end = 0; private void findTerminator() { auto r = _input.save.find!(not!isTerminator).find!isTerminator(); _end = _input.length - r.length; } this(Range input) { _input = input; if (!_input.empty) findTerminator(); else _end = size_t.max; } static if (isInfinite!Range) enum bool empty = false; // Propagate infiniteness. else @property bool empty() { return _end == size_t.max; } @property auto front() { return _input[0 .. _end]; } void popFront() { _input = _input[_end .. _input.length]; if (_input.empty) { _end = size_t.max; return; } findTerminator(); } @property typeof(this) save() { auto ret = this; ret._input = _input.save; return ret; } } // This will split on before the first element where pred is true, provided there are previous elements where pred is false: // void main() { "SomeGreatVariableName" .slicer!isUpper.writeln(); "someGGGreatVariableName".slicer!isUpper.writeln(); "".slicer!isUpper.writeln(); "a".slicer!isUpper.writeln(); "A".slicer!isUpper.writeln(); } // ["Some", "Great", "Variable", "Name"] ["some", "GGGreat", "Variable", "Name"] [] ["a"] ["A"] // This may or may not be what you wanted, depending on how you want to split "GGGreat". If you wanted it to simply split *ON* the left of every capital letter, then you can modify the the find terminator into: private void findTerminator() { auto r = _input.save.dropOne.find!isTerminator; _end = _input.length - r.length; } And you'd get: ["some", "G", "G", "Great", "Variable", "Name"] *** *** *** In any case, yeah, it shouldn't be too hard to shape it into what you want. A more involved solution to this problem could be to simply pass a "searchFun" predicate, in which case you'd be able to split not just according to any "unitary predicate", but according to an entire "range search strategy: // auto slicer(alias searchFun, Range)(Range input) if (((isRandomAccessRange!Range && hasSlicing!Range) || isSomeString!Range) && is(typeof(searchFun(input { return SlicerResult!(searchFun, Range)(input); } private struct SlicerResult(alias searchFun, Range) { private Range _input; private size_t _end = 0; private void findTerminator() { auto r = searchFun(_input.save); _end = _input.length - r.length; } ... // And then: "SomereatVariableName".slicer!((s)=>s.find!isLower.find!isUpper).writeln(); "someGGGreatVariableName" .slicer!((s)=>s.dropOne.find!isUpper).writeln(); ["Some", "reat", "Variable", "Name"] ["some", "G", "G", "Great", "Variable", "Name"] Just ideas.
Re: Basic dynamic array question. Use of new versus no new.
On Wednesday, 11 June 2014 at 05:46:07 UTC, Ali Çehreli wrote: On 06/10/2014 08:06 PM, Matt wrote: > On Wednesday, 11 June 2014 at 02:30:01 UTC, WhatMeWorry wrote: >> int[] array; // initially empty >> array.length = 5; // now has 5 elements >> >> while in Mr. Alexandrescu's book, it says >> >> To create a dynamic array, use a new expression (§ 2.3.6.1 on page 51) >> as follows: >> >> int[] array = new int[20]; // Create an array of 20 integers > I would have read the second as creating a static array of 20 ints in > heap memory, then assigning a dynamic array to point to it. Correct but it is not different from the first one, other than doing it in one step. Wait, what? That's not correct. "new int[20]" is simply "one of two" syntaxes to allocate an array of 20 ints, the other being "new int[](20)". It does NOT allocate a static array, and then slice it. Proof is that there is APPENDABLE data present, which should not happen if you had actually simply allocated a single element of type int[20] (APPENDABLE data is only present for array-style allocation). AFAIK, there is no "natural" way to allocate either a static array or a slice itslef, using new syntax. It can be done via the "wrapper struct" hack though: // //Used to allocate a slice "int[]". //Or a static array "int[20]" on the heap. struct NewWrapper(T) { T data; } void main() { int[] arr1 = new int[20]; int[] arr2 = (new NewWrapper!(int[20])).data[]; writeln(arr1.length); //20, as expected writeln(arr1.capacity); //31 on my machine writeln(arr2.length); //20 writeln(arr2.capacity); //0 } // Too bad the ambiguous syntax has us resolve to these tricks. It also prevents value constructing an array of elements. A syntax where the array sizes came *before* the type could have solved these issue: int size = 20; new size int[5]([1, 2, 3, 4, 5]); Allocate "20" (runtime) elements of type "int[5]", each initialized to the value ([1, 2, 3, 4, 5]). But, well, that ship has set sail long ago :(
Re: Splitting Ranges using Lambda Predicates
On Wednesday, 11 June 2014 at 11:42:42 UTC, Artur Skawina via Digitalmars-d-learn wrote: On 06/11/14 00:31, "Nordlöw" via Digitalmars-d-learn wrote: Either way, it shouldn't be too hard to implement. Base it off "splitter!pred", which is actually quite trivial. AFAIK, your What do you mean by basing it off splitter!pred - should I start with some existing splitter algorithm in Phobos or start from scratch? Starting from scratch is actually not a bad idea, at least for this kind of trivial functionality. A working version can be written in less time than copying, analyzing and modifying another implementation... ... artur I don't know about "starting from scratch" entirely. Maybe not copy paste, but it always helps to have a reference implementation. For example, you should avoid "countUntil" and "takeExactly" when dealing with strings, since these are not O(1) operations, and don't actually return string slices. EG: string s = "someGGGreatVariableName".slicer().front; Error: cannot implicitly convert expression (slicer("someGGGreatVariableName").front()) of type Result to string That's why the splitter code uses the more verbose "r.length - r.find!pred".
Re: Splitting Ranges using Lambda Predicates
On Wednesday, 11 June 2014 at 13:44:25 UTC, Artur Skawina via Digitalmars-d-learn wrote: There is a reason why I never use D's std lib. artur Well, (IMO) it's a problem with no real solution. But for what it's worth, most (if not all) of the algorithms in the standard lib know how to handle strings efficiently and correctly (split, find, etc...). Things only start getting funny once you start mixing indexing and element counts.
Re: Nameless Static Array
On Thursday, 12 June 2014 at 15:58:25 UTC, Taylor Hillegeist wrote: So, Lately I have been avoiding the NEW keyword. Why? Is malloc OK? I have recently given up static allocation of classes using CTFE. I guess they must be const or immutable? Funny, because you *are* allowed to default initialized a class member variable to a static class instance. And basically, it's just a thread local global. So you can "work around" with: // class MyClass { int i = 5; } void main() { static struct S { MyClass g = new MyClass(); } static S s; writeln(s.g.i); } // Disclaimer: Not sure if actually legal, or will cease to work in a few releases. So naturally i can do most of what i need to with structs. They are statically allocated no NEW necessary. But without the NEW strategy. I must allocate static arrays and set them to a pointer in my struct. Not too big of deal really. uint[12] Buffer; R_R_Buffer RRB=R_R_Buffer(Buffer); uint[24] OtherBuffer; R_R_Buffer RRB2 = R_R_Buffer(OtherBuffer); I feel though i might end up having OtherOtherOtherBuffers, and it pollutes my local symbols. I just dont like it. Is there a way to not give the buffer a name and do lika dis: R_R_Buffer RRB=R_R_Buffer(uint[12]); R_R_Buffer RRB2 = R_R_Buffer(uint[24]); This obviously fails to compile, but i think you get the idea. Mostly, I don't care what the static array name is. If you have a pointer, then at the end of the day *someone* *somewhere*, is going to have to declare and hold the buffers. That said, you could simply have a *single* static array that holds all your data. Furthermore, you could package it into a single convenient struct package: struct Buffer(T, size_t N) { T[N] buffer; size_t used; T[] getBufferSlice(size_t n) { assert(used + n <= N, "You've overused your buffer!"); auto low = used; used += n; return buffer[low .. used]; } ref T[n] getBufferSlice(size_t n)() { return *cast(T[n]*) getBufferSlice(n).ptr; } } void main() { Buffer!(int, 36) myData; int[] a= myData.getBufferSlice(12); int[24]* p = &myData.getBufferSlice!24(); } Notice that with this approach, you can extract a dynamic slice referencing stack data, if you don't know the size you want. If you statically know the size you want, then you can call your function template style, and have a more strongly typed return value, that can be passed by ref.
Re: Cannot alias null
On Thursday, 12 June 2014 at 20:44:16 UTC, H. S. Teoh via Digitalmars-d-learn wrote: On Thu, Jun 12, 2014 at 03:26:13PM -0500, Tom Browder via Digitalmars-d-learn wrote: This will not compile: alias blah = null; [...] 'null' is a value, not a type. Try: alias blah = typeof(null); T Yet you can alias variables... int i; alias j = i; So there's something special about "null".
Re: Cannot alias null
On Thursday, 12 June 2014 at 21:58:32 UTC, Adam D. Ruppe wrote: since null is a value maybe you want enum blah = null; you may also give it a type after the enum word I *think* the issue might be that "null" is an rvalue? Because you can alias variable names all you want. I do it all the time for templates where I *may* need a temporary. eg: void foo(T)(T val) { static if (isUnsigned!T) alias uval = val; else auto uval = unsigned(val); ... } It's also quite useful with varargs: alias a0 = args[0]; Also, you can't alias things like "int.init" either. I'm not sure the "rvalue" thing is the source, because these work: //struct S { static int i; static int j() @property; } alias a = S.i; alias b = S.j; // I'd consider filling a bug report.