bug, or is this also intended?
Unexpected auto-concatenation of string elements: string[] arr = ["a", "b" "c"];// ["a", "bc"], length==2 int[] arr2 = [[1], [2] [3]];// Error: array index 3 is out of bounds [2][0 .. 1] // Error: array index 3 is out of bounds [0..1] dmd 2.071.2-b2
Re: Meta-programming: iterating over a container with different types
On Friday, 23 September 2016 at 09:21:56 UTC, Claude wrote: ... // Maybe you can try using std.variant? import std.variant; alias Component = Variant; class Entity { void register (Component v) { components ~= v; } void unregister (T) () { foreach (i, c; components) if (c.type == typeid(T)) components = components[0..i] ~ components[i+1 .. $]; } Component getComponent (T) () { foreach (i, c; components) if (c.type == typeid(T)) return components[i]; } Component[] components; // iterating over the components alias components this; // or you can provide an inputRange interface by implementing // // bool empty () {} // Component front () {} // void popFront () {} // // to support whatever type of backing data structure you have. // (see http://ddili.org/ders/d.en/ranges.html) } unittest { import std.stdio; Entity e = new Entity(); e.register(Component(42)); e.register(Component("loire")); e.register(Component(3.14)); foreach (c; e) write(c, " "); writeln; // Prints 42 "loire" 3.14 e.unregister!string; foreach (c; e) write(c, " "); writeln; // Prints 42 3.14 e.unregister!double; foreach (c; e) write(c, " "); writeln; // Prints 42 e.unregister!int; assert(e.components.length == 0); }
Re: bug?
On Thursday, 15 September 2016 at 14:42:13 UTC, Jonathan M Davis wrote: On Thursday, September 15, 2016 14:07:18 deed via Digitalmars-d-learn wrote: On Thursday, 15 September 2016 at 13:57:13 UTC, rikki cattermole wrote: > Not a bug, it is never used. I'd expect an "Error: ... no effect ..." from the compiler. That would only work in fairly simplistic cases. For instance, if you were allocating an array of structs instead of an array of ints, then it _could_ have an effect. So, it's not an error that would catch much. And it's not like the code is doing anything illegal - just useless, which is why it gets optimized out. - Jonathan M Davis I dont't feel strongly about this at all, it was just my first reaction that it was a meaningless statement that the compiler should warn about or give an error on. I'm curious when you would need to do only `new Struct[](1000);` instead of `auto structs = new Struct[](1000);`? In case it was not clear, the code was: char[] str; // ... str.length = ... str[i] = ... and was intended to be updated to: char[] str = new char[](len); // ... str[i] = ... but somehow the line ended up as char[] str; new char[](len); // .. str[i] = ... // oops.
Re: bug?
On Thursday, 15 September 2016 at 13:57:13 UTC, rikki cattermole wrote: Not a bug, it is never used. I'd expect an "Error: ... no effect ..." from the compiler.
bug?
void main () { new int[](1); } Compiles with dmd 2.071.2-b2, but no code is generated for `new int[](1);`. Caused a bug due to: char[] arr; got updated to char[] arr; new char[](SIZE); If it's considered a bug and someone would file it, I'd be thankful.
Re: Chaining opIndex
On Monday, 9 May 2016 at 22:33:37 UTC, John Colvin wrote: There are lots of ways to approach this. Here's one possibility: auto cars(Bar bar) { static struct Res { Bar bar; Car opIndex(size_t i) { return /* e.g. getCar(bar, i); */ } } return Res(bar); } Thanks. Didn't think of function returning struct with opIndex. Having this as opCall in a struct Cars might be a solution. What other approaches did you have in mind?
Chaining opIndex
struct Foo { Bars bars; ... } struct Foos { Foo[] arr; Foo opIndex (size_t idx) { return arr[idx]; } ... } struct Bar { // No Car[] cars; ... } struct Bars { Bar[] arr; Bar opIndex (size_t idx) { return arr[idx]; } ... } struct Car { ... } Foos foos; Foo foo = foos[1]; // Works Bar bar = foos[1].bars[2]; // Works Car car = foos[1].bars[2].cars[3]; // Desired abstraction. For any Bar there are some Cars, but Bar doesn't hold any Cars. In other words, there could be a function Car cars (Bar bar, size_t idx) { ... }, but that would be called with parens; Car car = foos[i].bars[j].cars(k); which would be inconsistent and confusing. Defining struct Cars { Car opIndex (Bar bar, size_t idx) {} } and struct Bar { Cars cars; ... } doesn't enable chaining and then would have to be used like this, AFAIK: Car car = cars[foos[i].bars[j], k]; Which is out of the question. Any suggestions to achieve the desired abstraction in a clean manner?
Re: aliasing/referencing expressions in with statements
On Friday, 22 April 2016 at 01:42:11 UTC, Yuxuan Shui wrote: Maybe use something like: auto a = () => instanceA.verboseFieldA.verboseFieldB; You can certainly declare temporaries and rely on the compiler optimizing those away: auto a = instanceA.verboseFieldA.verboseFieldB; auto b = instanceA.aDescriptiveName; auto value = intanceC.value; // use a, b and value If that were considered a sound solution, it would partly undermine the purpose of with statements, except for referring to multiple fields within the same instance, which I guess is common enough and makes it more convenient to express member functions as free functions. However, it seems simple for the compiler to lower such a with statement, so I wonder whether there are any technical reasons not to? I.e: with (a = expressionA, b = expressionB, instanceC) { // access to instanceC's fields and replace a and b // with expressionA and expressionB, respectively. } That would make for very clear expressions while still allowing descriptive field names. Other solutions, as templates or mixins, seem a little too clumsy.
aliasing/referencing expressions in with statements
Often I find myself wanting to alias an expression, such as verbose fields, possibly nested. AFAIK, the with statement makes it easier, but not as good as it could have been. What I'd like to express is for example something like this: with( a = instanceA.verboseFieldA.verboseFieldB, b = instanceA.aDescriptiveName, instanceC) { // use a, b and value: b[value] = b[a + value] * (a*value)^^a; } // given: struct A { B verboseFieldA; int[] aDescriptiveName; ... } struct B { int verboseFieldB; ... } struct C { int value; ... } A instanceA; B instanceB; C instanceC; 1) Is it possible to achieve something similar in D now? And if not: 2) Are there any implementation considerations in this direction, extending the with statement?
Re: Set cursor position in a file
On Sunday, 10 April 2016 at 16:19:51 UTC, Lucien wrote: Hello, Is there the possibility to set the cursor position in a file ? Example: void main() { File myFile = File("myFile.txt"); showFile(myFile); // set cursor pos to 0 showFile(myFile); } void showFile(File f) { while (!f.eof()) { write(f.readln()); } } Thanks in advance. See std.stdio.File.seek. For your example, if all you want to do is to write a file to std.out: --- import std.file : read; import std.stdio : write; string file = cast(string) read("filename.txt"); write(file); ---
Re: Ternary if and ~ does not work quite well
On Monday, 12 October 2015 at 15:39:15 UTC, TheFlyingFiddle wrote: How does this compile? { string str = "hello"; foreach (n; [32, 119, 111, 114, 108, 100, 33]) str ~= n; import std.stdio : writeln; str.writeln;// prints "hello world!" writeln(true == 1); // true writeln(false == 0);// true string str2 = str.dup; str ~= 0; str2 ~= false; writeln(str == str2); // true str ~= 1; str2 ~= true; writeln(str == str2); // true }
Re: reading file byLine
On Monday, 14 September 2015 at 18:36:54 UTC, Meta wrote: As an aside, you should use `sort()` instead of the parentheses-less `sort`. The reason for this is that doing `arr.sort` invokes the old builtin array sorting which is terribly slow, whereas `import std.algorithm; arr.sort()` uses the much better sorting algorithm defined in Phobos. Thanks for pointing out.
Re: reading file byLine
On Sunday, 13 September 2015 at 03:20:31 UTC, deed wrote: ... and since `string` is an alias for `const(char)[]`, it's not ... string is an alias for immutable(char)[], not const(char)[]. http://dlang.org/arrays.html#strings Sorry about the noise.
Re: reading file byLine
On Sunday, 13 September 2015 at 03:20:31 UTC, deed wrote: string s = "Some text"; s.retro.find("e"); // `Some te` (Surprising to me. Error? 2.067.1) Sorry, the above is wrong, .retro.find does indeed return what's expected. string s = "Some text"; s.retro.find("e").writeln; // Prints `et emoS`, as expected.
Re: reading file byLine
On Saturday, 12 September 2015 at 12:51:04 UTC, Namal wrote: Anyway, there is no .reverse for strings I guess, what is the way to completely reverse a string in D? What do you want to do? Do you want to keep your data in original order, but get a reversed view of it for something, or do you actually want to reverse your original array? You can use `retro` to simply read your array backwards, i.e.: string s = "Some text"; s.retro.writeln; // `txet emoS` s.writeln; // `Some text` s.retro.find("e"); // `Some te` (Surprising to me. Error? 2.067.1) s.retro.until("e").writeln;// `tx` s.find("e"); // `Some` The string is still kept in original order, but `retro` returns a range reading the array backwards. If you want to store a reversed string in memory, that's possible too, of course. One way of doing it, is to convert your retro range to a string: s = s.retro.to!string; s.writeln; // `txet emoS` This will allocate new memory for the reversed copy and assign it to `s`. Reverse is an algorithm that swaps values at different indices and since `string` is an alias for `const(char)[]`, it's not allowed. It means that each element of the array is const, so you cannot mutate any elements, but you can append or remove elements or assign the slice to view another part of the string or some other string. Hence, a `s.reverse` will give you an error. If you use `char[]` instead of `const(char)[]` you can use reverse and reuse the same memory for the reversed `char[]`. To illustrate: char[] t = ['a', 'b', 'c']; std.algorithm.reverse(t); t.writeln; // `cba` // s[0] = s[$-1]; // Error, cannot mutate const elements auto r = s.retro; s.length = 0; r.each!(e => s ~= e); s.writeln; // s has the reversed string, obtained through // a temporary range object, setting length to // zero and appending the elements from the // range, which is allowed for const(char)[]
Re: Adjacent Pairs Range
On Saturday, 12 September 2015 at 10:17:19 UTC, Nordlöw wrote: How do I most elegantly iterate all the adjacent pairs in an `InputRange` using Phobos? Something like [1,2,3,4] => [(1,2), (2,3), (3,4)] Why not just: zip(arr[0 .. $-1], arr[1 .. $]) ?
Re: Lazy sort
On Friday, 11 September 2015 at 10:41:16 UTC, ixid wrote: Does sort have to be eager or would it be possible to have a lazy version? It's messy to always have to use array and leap in and out of lazy operations within a UFCS chain. Surely as many functions as possible should be optionally lazy. Wouldn't that mean removing min or max lazily?
Re: using std.algorithm to find intersection of DateTime[][] arg
On Wednesday, 9 September 2015 at 20:28:35 UTC, Laeeth Isharc wrote: I have a DateTime[][] arg ... I would like to find the intersection of the dates. A suggestion: auto minLength = arg.map!(a => a.length).reduce!min; auto minIdx = arg.map!(a => a.length).countUntil(minLength); auto intersection = arg[minIdx].filter!(e => chain(arg[0..minIdx], arg[minIdx..$]).all!(a => a.assumeSorted.contains(e))); reduce with setIntersection seems the most straightforward, but needs array AFAIK, i.e.: auto intersection = //reduce!((r, x) => setIntersection(r, x))(arg); // doesn't work reduce!((r, x) => setIntersection(r, x).array)(arg);// does, but with array
Re: What is "FilterResult" type?
On Wednesday, 9 September 2015 at 11:30:26 UTC, Bahman Movaqar wrote: On Wednesday, 9 September 2015 at 08:29:20 UTC, cym13 wrote: The way I would have written it is: auto result = foobars.filter!(fb => nums.all!(n => (fb.x * fb.y) > n)) .filter!(fb => nums.all!(n => fb.x < n && fb.y < n)); For the lame example I gave, something similar occurred to me at first; but then I thought 4 `filter`s (assuming `all` is simply a `filter`) might be non-idiomatic as it might incur some performance penalty. Note that this can easily be rewritten with only one `filter` and one `all`: auto result = foobars.filter!( fb => nums.all!( n => fb.x * fb.y > n && fb.x < n && fb.y < n));
Re: reading file byLine
On Sunday, 6 September 2015 at 22:04:55 UTC, Namal wrote: oh, sorry. But I found out what I have been doing wrong besides that. arr.sort.uniq; uniq(arr) or arr.sort.uniq; compiles but doesn't store it in the arr array, I need to store it in a new one. Right, it's like int x = 3; // x + 5; // Just an expression evaluated to 8, // but what do you want to do with it? // It won't affect your program and the // compiler will give you an error. int y = x + 5; // But you can assign the expression to // a new variable x = x + 5; // or you can assign it back writeln(x);// or you can pass it to a function. // For your case: int[] arr = [1, 2, 3, 2, 1, 4]; arr.sort; // Operating on arr in place -> arr itself is mutated arr.writeln; // [1, 1, 2, 2, 3, 4] arr.uniq; // Not operating on arr, it's like the expression // x + 5 (but no compiler error is given). arr.uniq.writeln; // [1, 2, 3, 4] (Expression passed to writeln) arr.writeln; // [1, 1, 2, 2, 3, 4] (Not affected) int[] newArr = arr.uniq.array; // Expression put into a new array assigned to newArr newArr.writeln;// [1, 2, 3, 4] arr.writeln; // Still the sorted array. [1, 1, 2, 2, 3, 4] arr = arr.uniq.array; // Now arr is assigned the uniq array arr.writeln; // [1, 2, 3, 4] You need to know whether the function will mutate your array; sort does, while uniq doesn't. If you want to do things requiring mutation, but still want your original data unchanged, you can duplicate the data with .dup before the mutating operations, like this: int[] data = [1, 2, 2, 1]; int[] uniqData = data.dup.sort.uniq.array; data.writeln; // [1, 2, 2, 1] Unchanged, a duplicate was sorted. uniqData.writeln; // [1, 2]
Re: reading file byLine
On Monday, 7 September 2015 at 10:25:09 UTC, deed wrote: writeln(x);// or you can pass it to a function. I meant `writeln(x + 5)`
Re: reading file byLine
On Sunday, 6 September 2015 at 17:57:49 UTC, Namal wrote: Yeah, I just checked, it is 2.066, how can I install the new version on ubuntu with sudo apt-get? sudo apt-get install dmd will give you dmd v2.067.1. Don't know when it will be upgraded to 2.068 though.
Re: reading file byLine
On Saturday, 5 September 2015 at 17:31:39 UTC, Namal wrote: Yeah, I have have been trying this example from wiki books https://en.wikibooks.org/wiki/Learning_D_With_Project_Euler It is not even compiling. What exactly is not compiling?
Re: reading file byLine
On Saturday, 5 September 2015 at 14:44:19 UTC, deed wrote: .map!(s => chomp(s, "\"") .map!(s => chompPrefix(s, "\"") should be .map!(s => chomp(s, "\"")) .map!(s => chompPrefix(s, "\""))
Re: reading file byLine
On Saturday, 5 September 2015 at 12:41:37 UTC, Namal wrote: Thx guys. Now I try out the split function. I read the file as a single string? auto arr = split(cast(string)read(filename),","); where the file has "A", "B", "C" and I get the output ["\"A\"", " \"B\"", " \"C\"\n"] I can understand that read functions reads the endl but what does it with the quotation marks? how can I modify read so I get just ["A", "B", "C"] '\' is the escape character and is used to disambiguate start or end of string (") and a quotation mark within the string (\"), the same way as "\n" means newline and not '\' 'n', which would have been "\\n". So what you have is [`"A"`, ` "B"`, ` "C"\n`], if you use ` for start\stop of string. You say you want ["A", "B", "C"], so you need to remove whitespace. You can do that with std.string.strip. Assuming you also want to remove the quotation marks present in the file, one solution is to use std.string.chomp and std.string.chompPrefix, for example: string s = cast(string) read(filename); s.split(",") .map!strip .map!(s => chomp(s, "\"") .map!(s => chompPrefix(s, "\"") .writeln ;
Re: reading file byLine
On Friday, 4 September 2015 at 07:27:54 UTC, Namal wrote: On Friday, 4 September 2015 at 01:55:13 UTC, deed wrote: On Friday, 4 September 2015 at 01:31:28 UTC, Namal wrote: How can I get just the maximum element? Do I need to give a range for it? Use max? http://dlang.org/phobos/std_algorithm_comparison.html#max Sorry, I don't understand the syntax yet. How do I tell max to search all elements? You can search all elements by using reduce http://dlang.org/phobos/std_algorithm_iteration.html#reduce I mean, why does sort(myarray) is legit and max(myarray) isn't. I don't know why, other than that is the current design in Phobos. import std.algorithm, std.range, std.array, std.string, std.stdio, std.conv; int[] arr1 = [1, 2, 30]; //arr1.max.writeln; // Doesn't work, as you say arr1.reduce!max.writeln;// This does. Prints 30. int[] arr2 = [4, 5, 6]; int[][] arr = [arr1, arr2]; arr.reduce!max.writeln; // Returns either arr1 or arr2. Element by // element comparison until one is greatest. // Prints arr2, since 1 < 4. arr.joiner.reduce!max.writeln; // Flattens arr1 and arr2 to one arr and // finds max. Prints 30. //For your example: auto f = File("filename", "r"); auto numbers = f// 1 2 3\n4 5 6 .byLine // ["1 2 3", "4 5 6"] .map!(a => a.split) // [["1", "2", "3"], ["4", "5", "6"]] .map!(a => a.to!(int[]))// [[1, 2, 3], [4, 5, 6]] .array; // Allocates and puts the elements into an // int[][] for reuse of state. numbers // [[1, 2, 3], [4, 5, 6]] .map!(reduce!max) // [3, 6] .writeln; // prints [3, 6] numbers // [[1, 2, 3], [4, 5, 6]] .joiner // [1, 2, 3, 4, 5, 6] .reduce!max // 6 .writeln; // prints 6
Re: reading file byLine
On Friday, 4 September 2015 at 01:31:28 UTC, Namal wrote: How can I get just the maximum element? Do I need to give a range for it? Use max? http://dlang.org/phobos/std_algorithm_comparison.html#max
Re: Struct template
static if (is(typeof(T) == int)) should be static if (is(T == int)) T is already a type. Ahh. Thanks!
Struct template
struct Internal { int i; double d; string s; } struct External_int { Internal internal; @property Internal* ptr () { return &internal; } this (int a) { internal.s = "int"; internal.i = a; } } struct External (T) { Internal internal; @property Internal* ptr () { return &internal; } static if (is(typeof(T) == int)) { this (T a) { internal.s = "int"; internal.i = a; } } } void main () { auto e1 = External_int(1); // Ok auto e2 = External!int(1); // Nope, cannot implicitly // convert expression (1) // of type int to Internal } Why? And how is this fixed? Thanks.
Re: win64 - win32.oaidl.VARIANT -> error LNK2019
Your link is failing because the .init value of the struct is not found. The .init will be in the object file corresponding to the module where the struct is defined, so to fix the linker error, add the win32.oaidl module to the list of modules you're compiling and linking. An easy way to do that is to use rdmd instead of dmd to build your program. Thank you for your prompt reply and maintaining the bindings on GitHub! I used dub (with dmd). The win32 files reside in another directory and the path is specified in "importPaths". If I understand you correctly, the oaidl.d file should also be specified in "sourceFiles" in the .json file?
win64 - win32.oaidl.VARIANT -> error LNK2019
// bindings from https://github.com/CS-svnmirror/dsource-bindings-win32/blob/308739a417eaaba85a5d3ce7741fd43d3042efe0/oaidl.d --- import win32.oaidl; // The following gives linker error: error LNK2019: unresolved external // symbol _D5win325oaidl7VARIANT6__initZ referenced // in function ... VARIANT v; v.vt = VARENUM.VT_I4; v.lVal = 1; // while this works - no linker error VARIANT v = { vt: VARENUM.VT_I4, lVal: 1 }; Defining a similar structure as VARIANT with anonymous structs and unions targeting linux seemed to work fine without linker problems. What is the idiomatic way of handling this on win64?
Re: Bug?
OK, I tried with OSX 64-bit compiler. Perhaps 32 bit would not fare as well. What platform are you testing on? Have tried Linux and Windows 64-bit and it seems to be an issue when compiled with -m32. Tests are provided here http://dpaste.dzfl.pl/5f55f4152aa8. I agree that one cannot compare double and real and expect equality, so the ones marked with [1] are not incorrect behaviour, while [2] and [4] seem to be bugs.
Re: Bug?
On Thursday, 23 October 2014 at 21:42:46 UTC, anonymous wrote: On Thursday, 23 October 2014 at 21:17:25 UTC, deed wrote: Some testing can be found on http://dpaste.dzfl.pl/5f55f4152aa8 for both Windows and Linux. This just illustrates the sin function. I think the tests marked "[1]" are expected to fail. They involve converting one operand of the comparison to double, but not the other. The comparison is done using real precision. So, one operand goes through a real->double->real conversion, which changes the value. You're right about those marked [1]; sin returns real and shouldn't be expected to equal the same value truncated to double or float and then extended back to real. Converting the sin to double and compare is expected to work for those, and it does when compiled with -m64, but not with -m32, on Linux: -- import std.math : sin; import std.conv : to; double fun (double a) { return sin(a); } immutable double a = 3. assert (fun(a) == sin(a).to!double); // Works when compiled with -m64 -- The behaviour of those only marked [2] and [4] (the 32-bit versions) seems to be a bug.
Re: Bug?
Some testing can be found on http://dpaste.dzfl.pl/5f55f4152aa8 for both Windows and Linux. This just illustrates the sin function. Replacing double with real makes everything pass on Linux Mint 16 with -m32 and -m64. Replacing double with float seems to give the same problems as before, but hasn't been extensively tested. It seems very likely to be a conversion issue, as H. S. Teoh mentioned.
Re: Bug?
A similar problem was recently (about 2-3 weeks ago IIRC) seen in one of the Phobos PR's. It appears to be related to the autoextension of float to double (or double to real, I forget which) in certain contexts on Windows. @deed Could you please try to reduce the failing test to a minimal code example, and post a disassembly of the concerned function(s)? This could either be a subtle codegen bug, or something more fundamentally broken with 80-bit real support. T Some testing can be found on http://dpaste.dzfl.pl/5f55f4152aa8 for both Windows and Linux. This just illustrates the sin function.
Re: Bug?
On Thursday, 23 October 2014 at 18:26:53 UTC, Steven Schveighoffer wrote: On 10/23/14 2:18 PM, deed wrote: Using equality is not a good idea with floating point. The compiler will on a whim, or depending on whether it can inline or not, use higher precision floats, changing the outcome slightly. I cannot say for certain whether this explains all the issues you have, the very last one seems troubling to me at least. Sure, in many cases it's a bad idea. While I understand that sin(PI) != 0.0, but approxEqual(sin(PI), 0.0) == true, I would expect the following to pass: assert (0.0 == 0.0); assert (1.2345 == 1.2345); F a = 1.2345, b = 9.8765; assert (a+b == b+a); assert (a*b == b*a); None of these fail on my system Same for me, that's the point; it's perfectly valid to compare floating points. F fun (F a) pure; assert (fun(a) + fun(b) == fun(b) + fun(a)); assert (fun(a) * fun(b) == fun(b) * fun(a)); auto a = fun(100); auto b = fun(100); assert (a == b); assert (fun(100) == fun(100)); Not sure what body of fun is, so I cannot test this. Could be anything taking a floating point and returning a floating point. You would expect to get the same back for the same input, especially when it's pure. If so, the asserts above are expected to hold. Now, if fun's body is { return sin(a); }, the behaviour changes to: auto c = fun(100); auto d = fun(100); assert (c == d); // Ok assert (fun(100) != fun(100)) // I have a hard time understanding // this is correct behaviour Tried that out, it does not fail on my machine. Can you be more specific on your testing? What compiler/platform? Stock compiler, or did you build it yourself? Right. It doesn't fail, and that's the problem. assert (fun(100) == fun(100)); // Should pass, and does with // body { return a + 1; } // but not with // body { return sin(a); } assert (fun(100) != fun(100)); // Shouldn't pass, but passes with // body { return sin(a);} Compiler: DMD32 D Compiler v2.066.0 Also tried dpaste.dzfl.pl with 2.065.0 and DMD 2.x Git (cfb5842b49), which had slightly different behaviour; more of the sin tests which should pass in my opinion did with those two. Hence, it appears to be regressions. -Steve
Re: Bug?
Using equality is not a good idea with floating point. The compiler will on a whim, or depending on whether it can inline or not, use higher precision floats, changing the outcome slightly. I cannot say for certain whether this explains all the issues you have, the very last one seems troubling to me at least. -Steve Sure, in many cases it's a bad idea. While I understand that sin(PI) != 0.0, but approxEqual(sin(PI), 0.0) == true, I would expect the following to pass: assert (0.0 == 0.0); assert (1.2345 == 1.2345); F a = 1.2345, b = 9.8765; assert (a+b == b+a); assert (a*b == b*a); F fun (F a) pure; assert (fun(a) + fun(b) == fun(b) + fun(a)); assert (fun(a) * fun(b) == fun(b) * fun(a)); auto a = fun(100); auto b = fun(100); assert (a == b); assert (fun(100) == fun(100)); Now, if fun's body is { return sin(a); }, the behaviour changes to: auto c = fun(100); auto d = fun(100); assert (c == d); // Ok assert (fun(100) != fun(100)) // I have a hard time understanding // this is correct behaviour
Re: Bug?
assert (fasin(a) != fasin(a)); // ? assert (facos(a) != facos(a)); // ? Too quick there.. But: assert (fasin(0.5) != fasin(0.5)); // ? assert (facos(0.5) != facos(0.5)); // ?
Re: Bug?
-- Why bother? import std.algorithm : max; F fun (F a, F b) { return max(a,b) + 1.; } unittest { assert (gun(1, 2) == gun(2, 1)); } // Passes F pun (F a, F b) { return sin(max(a,b)); } unittest { assert (fun(1, 2) == fun(2, 1)); } // Fails // Fun, gun, pun... unittest { assert (fun(1, 2) == fun(2, 1)); } // Passes unittest { assert (pun(1, 2) == pun(2, 1)); } // Fails
Bug?
// DMD v2.066.0 // All asserts pass (!) import std.math : sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh; alias F = double; immutable F a = 3, b = 5; F fmul (F a) pure { return a * b; } F fsin (F a) pure { return sin(a); } struct Smul { F value; this (F a) { value = a * b; } alias value this; } struct Ssin { F value; this (F a) { value = sin(a); } alias value this; } F ans_mul = fmul(a); F ans_sin = fsin(a); Smul smul = Smul(a); Ssin ssin = Ssin(a); // All combinations of a*b, fmul(a), Smul(a), ans_mul and smul pass // the equality test. E.g.: assert (a*b == a*b); assert (a*b == fmul(a)); assert (a*b == Smul(a)); assert (a*b == ans_mul); assert (a*b == smul); assert (fmul(a) == fmul(a)); assert (fmul(a) == Smul(a)); assert (fmul(a) == ans_mul); assert (fmul(a) == smul); // However, for std.math.sin it's different: assert (sin(a) == fsin(a));// But not in 2.065 assert (sin(a) != Ssin(a));// ? assert (sin(a) != ans_sin);// ? assert (sin(a) != ssin); // ? assert (fsin(a) != fsin(a)); // ? assert (fsin(a) != Ssin(a)); // ? assert (fsin(a) != ans_sin); // ? assert (fsin(a) != ssin); // ? // Same goes for cos, tan, asin, acos, atan: F fcos (F a) { return cos(a); } F ftan (F a) { return tan(a); } F fasin (F a) { return asin(a); } F facos (F a) { return acos(a); } F fatan (F a) { return atan(a); } assert (fcos(a) != fcos(a)); // ? assert (ftan(a) != ftan(a)); // ? assert (fasin(a) != fasin(a)); // ? assert (facos(a) != facos(a)); // ? assert (fatan(a) != fatan(a)); // ? // And then it goes only downhill for // sinh, cosh, tanh, asinh, acosh and atanh: assert (sinh(a)!= sinh(a));// ? assert (cosh(a)!= cosh(a));// ? assert (tanh(a)!= tanh(a));// ? assert (asinh(a) != asinh(a)); // ? assert (acosh(a) != acosh(a)); // ? assert (atanh(0.5) != atanh(0.5)); // ? -- Why bother? import std.algorithm : max; F fun (F a, F b) { return max(a,b) + 1.; } unittest { assert (gun(1, 2) == gun(2, 1)); } // Passes F pun (F a, F b) { return sin(max(a,b)); } unittest { assert (fun(1, 2) == fun(2, 1)); } // Fails
Re: Error: array operation d1[] + d2[] without assignment not implemented
Hi! struct Vector (T) { T[]arr; T[] opSlice() { return arr; } } Vector!double v; double[] d; v[][] = d[] + d[]; //first [] call opSlise, second [] for array syntax Best Regards, Ilya Thanks for your suggestion. It's not as attractive though, it would be the same as v.arr[] = ..., exposing the naked array. The syntax also becomes a bit confusing. With alias this it works, but functionality is lost. See http://dpaste.dzfl.pl/35081c1f1745 It feels not consistent, so I guess that's the reason for the "not implemented" message.
Error: array operation d1[] + d2[] without assignment not implemented
struct Vector (T) { T[]arr; void opSliceAssign (T[] a) { arr[] = a[]; } } unittest { auto v = Vector!double([1, 2]); double[] d1 = [11, 12]; double[] d2 = [21, 22]; double[] d3 = new double[](2); d3[] = d1[] + d2[]; assert (d3 == [11.+21., 12.+22.]); assert (is(typeof(d1[] + d2[]) == double[])); v[] = d1[] // Fine v[] = d1[] + d2[]; // Error: array operation d1[] + d2[] without assignment not implemented } How can opSliceAssign be defined to make this work?