What's opIndexAssign supposed to return ?
Lets say I've got 3 overloads of opIndexAssign: auto opIndexAssign(T t); auto opIndexAssign(T t, size_t i); and auto opIndexAssign(T t, size_t[2] i); I would assume to return what I would return with opIndex but I'd rather not act upon assumptions. But if yes is it supposed to be the newly assigned values or the pre-assignment ones ? By value or by reference ? And if it's the new stuff can I just return t ? The language manual on operator overloading didn't answer that question and neither did an internet search which didn't find any useful information. Something unrelated and a heads up about introducing opIndexAssign from 2004.
Re: What's opIndexAssign supposed to return ?
On Tuesday, 25 February 2020 at 11:02:40 UTC, wjoe wrote: Lets say I've got 3 overloads of opIndexAssign: auto opIndexAssign(T t); auto opIndexAssign(T t, size_t i); and auto opIndexAssign(T t, size_t[2] i); I would assume to return what I would return with opIndex but I'd rather not act upon assumptions. But if yes is it supposed to be the newly assigned values or the pre-assignment ones ? By value or by reference ? And if it's the new stuff can I just return t ? The language manual on operator overloading didn't answer that question and neither did an internet search which didn't find any useful information. Something unrelated and a heads up about introducing opIndexAssign from 2004. opIndexAssign is the operator used in the following code: arr[1] = 8; It returns the element at index 1 (so 8 in this case) by reference. This allows you to do: (arr[1] = 8)++; assert(arr[1] == 9); Whether or not you want to support this behavior in your custom data structure is up to you. It's perfectly valid to return the element by value or even return void. Returning void from any custom assignment operator is always a safe choice. It's possible that some algorithms (e.g. in Phobos or third-party libraries) may need op*Assign to return something, but in that unlikely case you'll get a compile-time error, so it will be an easy fix.
Re: What's opIndexAssign supposed to return ?
On Tuesday, 25 February 2020 at 11:49:50 UTC, Petar Kirov [ZombineDev] wrote: On Tuesday, 25 February 2020 at 11:02:40 UTC, wjoe wrote: [...] opIndexAssign is the operator used in the following code: arr[1] = 8; It returns the element at index 1 (so 8 in this case) by reference. This allows you to do: (arr[1] = 8)++; assert(arr[1] == 9); Whether or not you want to support this behavior in your custom data structure is up to you. It's perfectly valid to return the element by value or even return void. Returning void from any custom assignment operator is always a safe choice. It's possible that some algorithms (e.g. in Phobos or third-party libraries) may need op*Assign to return something, but in that unlikely case you'll get a compile-time error, so it will be an easy fix. Excellent answer ! Thanks for your fast reply :)
Re: What's opIndexAssign supposed to return ?
On 2/25/20 3:02 AM, wjoe wrote:> Lets say I've got 3 overloads of opIndexAssign: > > auto opIndexAssign(T t); > an internet search which didn't find any useful > information. I have examples for non-templatized and templatized versions of opIndexAssign here: http://ddili.org/ders/d.en/operator_overloading.html#ix_operator_overloading.opIndexAssign http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.opIndexAssign%20template I used this index to find those: http://ddili.org/ders/d.en/ix.html Ali
Re: 2D matrix operation (subtraction)
On Saturday, 22 February 2020 at 08:29:32 UTC, 9il wrote: [snip] Maybe mir.series [1] can work for you. I had a few other thoughts after looking at septc's solution of using y[0..$, 0] *= 100; to do the calculation. 1) There is probably scope for an additional select function to handle the use case of choosing a specific row/column. For instance, what if instead of y[0..$, 0] you want y[0..$, b, 0..$] for some arbitrary b. I think you would need to do something like y.select!1(b, b + 1); which doesn't have the best API, IMO, because you have to repeat b. Maybe just an overload for select that only takes one input instead of two? 2) The select series of functions does not seem to work as easily as array indexing does. When I tried to use the select/selectFront functions to do what he is doing, I had to something like auto z = y.selectFront!1(1); z[] *= 100; This would adjust y as expected (not z). However, I couldn't figure out how to combine these together to one line. For instance, I couldn't do y.selectFront!1(1) *= 100; or auto y = x.selectFront!1(1).each!(a => a * 100); though something like y[0..$, 0].each!"a *= 100"; works without issue. It got a little frustrating to combine those with any kind of iteration. TBH, I think more than the select functions, the functionality I would probably be looking for is more what I was doing with byDim!1[0] in the prior post. I could imagine some very simple version looking like below auto selectDim(size_t dim, T)(T x, size_t a, size_t b) { return byDim!dim[a .. b]; } with a corresponding version auto selectDim(size_t dim, T)(T x, size_t a) { return byDim!dim[a .. (a + 1)]; } This simple version would only work with one dimension, even though byDim can handle multiple.
Re: What's opIndexAssign supposed to return ?
On Tuesday, 25 February 2020 at 15:30:19 UTC, Ali Çehreli wrote: On 2/25/20 3:02 AM, wjoe wrote:> Lets say I've got 3 overloads of opIndexAssign: > > auto opIndexAssign(T t); > an internet search which didn't find any useful > information. I have examples for non-templatized and templatized versions of opIndexAssign here: http://ddili.org/ders/d.en/operator_overloading.html#ix_operator_overloading.opIndexAssign http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.opIndexAssign%20template I used this index to find those: http://ddili.org/ders/d.en/ix.html Ali This is great! Thank you. Curious why this wasn't found by my internet search.
library dependencies nightmare, D edition
Hello! I have two libraries, where library B depends on library A, where both libraries consist of multiple packages. Say my project (I'm using VisualD) folder layout is the following: C/: libA A_Package1 A_Package2 A_Package3 libB B_Package1 - Imports from libA.Package2 B_Package2 B_Package3 Executable Module - Imports from libB.Package1 Why am I getting "Error: module "Package1" is in file libA\Package2 which cannot be read" messages? I tried changing the folder layout so that LibA is inside a dependencies folder inside LibB, but nothing changed. What am I missing?
Re: library dependencies nightmare, D edition
On 2/25/20 4:31 PM, Marcel wrote: Hello! I have two libraries, where library B depends on library A, where both libraries consist of multiple packages. Say my project (I'm using VisualD) folder layout is the following: C/: libA A_Package1 A_Package2 A_Package3 libB B_Package1 - Imports from libA.Package2 B_Package2 B_Package3 Executable Module - Imports from libB.Package1 Why am I getting "Error: module "Package1" is in file libA\Package2 which cannot be read" messages? I tried changing the folder layout so that LibA is inside a dependencies folder inside LibB, but nothing changed. What am I missing? It would be most helpful to have actual messages, because you might be missing something. Several causes for such errors: 1. You are trying to read a file that it cannot find given the command line parameters 2. The file has a module that is different from the actual package/file it is in. Could be something else too. Maybe you have the same package name from both libraries? That should work, as long as you don't define the same module in both packages. -Steve
Re: library dependencies nightmare, D edition
On Tuesday, 25 February 2020 at 21:48:00 UTC, Steven Schveighoffer wrote: On 2/25/20 4:31 PM, Marcel wrote: Hello! I have two libraries, where library B depends on library A, where both libraries consist of multiple packages. Say my project (I'm using VisualD) folder layout is the following: C/: libA A_Package1 A_Package2 A_Package3 libB B_Package1 - Imports from libA.Package2 B_Package2 B_Package3 Executable Module - Imports from libB.Package1 Why am I getting "Error: module "Package1" is in file libA\Package2 which cannot be read" messages? I tried changing the folder layout so that LibA is inside a dependencies folder inside LibB, but nothing changed. What am I missing? It would be most helpful to have actual messages, because you might be missing something. Several causes for such errors: 1. You are trying to read a file that it cannot find given the command line parameters 2. The file has a module that is different from the actual package/file it is in. Could be something else too. Maybe you have the same package name from both libraries? That should work, as long as you don't define the same module in both packages. -Steve I can't give you the actual error messages right now, but both libraries have packages that define modules with the same name. For example, both libraries have packages with a module called "utility.d". Unfortunately, this isn't the only thing that causes compilation to fail though.
Re: library dependencies nightmare, D edition
On 2/25/20 5:26 PM, Marcel wrote: I can't give you the actual error messages right now, but both libraries have packages that define modules with the same name. For example, both libraries have packages with a module called "utility.d". Unfortunately, this isn't the only thing that causes compilation to fail though. is this imported via: import utility; ? or is it import packagea.utility; ? If the former, then that is definitely a problem I think. Two libraries can have the same package name, but cannot have the same top-level module name (you can't split modules). But I think you might have a different error for that condition. Make sure that whatever module it is complaining about has a correct module declaration in both libraries. i.e. even if you have: packagea/utility.d packageb/utility.d and you import via: import packagea.utility; make sure packagea/utility.d has the module declaration: module packagea.utility; -Steve
Re: library dependencies nightmare, D edition
On Tue, Feb 25, 2020 at 10:26:48PM +, Marcel via Digitalmars-d-learn wrote: [...] > I can't give you the actual error messages right now, but both > libraries have packages that define modules with the same name. For > example, both libraries have packages with a module called > "utility.d". Unfortunately, this isn't the only thing that causes > compilation to fail though. Are these top-level modules? If they are contained under packages, e.g., package1.utility vs. package2.utility, it shouldn't be a problem. >From what you described, though, it looks like your compile command is missing some -I flags. I don't use VisualD so I can't help you in the details, but if there's some settings somewhere for include paths, that might be what you need to fix this problem. T -- People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird. -- D. Knuth
Re: library dependencies nightmare, D edition
On Tuesday, 25 February 2020 at 22:26:48 UTC, Marcel wrote: For example, both libraries have packages with a module called "utility.d". This is why I now have a strict policy that ALL modules must have at least a two part name; company.utility or whatever. alas not everyone follows that :(
Re: library dependencies nightmare, D edition
On Tuesday, 25 February 2020 at 22:35:07 UTC, Steven Schveighoffer wrote: On 2/25/20 5:26 PM, Marcel wrote: I can't give you the actual error messages right now, but both libraries have packages that define modules with the same name. For example, both libraries have packages with a module called "utility.d". Unfortunately, this isn't the only thing that causes compilation to fail though. is this imported via: import utility; ? or is it import packagea.utility; ? If the former, then that is definitely a problem I think. Two libraries can have the same package name, but cannot have the same top-level module name (you can't split modules). But I think you might have a different error for that condition. Make sure that whatever module it is complaining about has a correct module declaration in both libraries. i.e. even if you have: packagea/utility.d packageb/utility.d and you import via: import packagea.utility; make sure packagea/utility.d has the module declaration: module packagea.utility; -Steve The issue isn't with the module declaration, it is declared and imported as package1.utility. I think its an issue with VisualD's feature of adding import paths of project dependencies...
Strange counter-performance in an alternative `decimalLength9` function
So after reading the translation of RYU I was interested too see if the decimalLength() function can be written to be faster, as it cascades up to 8 CMP. After struggling with bad ideas I finally find something that looks nice: - count the leading zero of the input - switch() this count to have in the worst of the cases only 1 CMP (when the bit number possibly changes the digit count, e.g 9 -> 10 (when bsr(input) == 4) after writing all the values allowing to know the cases where a comparison is necessary... min2 = 0b10 max2 = 0b11 min3 = 0b100 max3 = 0b111 ... ... min32 = 0b100...0 max32 = 0b111...1 ...I finally write the "nice" thing. --- #!dmd -boundscheck=off -O -release -inline import std.stdio; ubyte decimalLength9(const uint v) { if (v >= 1) { return 9; } if (v >= 1000) { return 8; } if (v >= 100) { return 7; } if (v >= 10) { return 6; } if (v >= 1) { return 5; } if (v >= 1000) { return 4; } if (v >= 100) { return 3; } if (v >= 10) { return 2; } return 1; } ubyte fdecimalLength9(const uint v) pure nothrow { import core.bitop; const ubyte lzc = cast(ubyte) (bsr(v) + 1); ubyte result; switch (lzc) { case 0 : case 1 : case 2 : case 3 : result = 1; break; case 4 : result = v >= 10 ? 2 : 1; break; case 5 : case 6 : result = 2; break; case 7 : result = v >= 100 ? 3 : 2; break; case 8 : case 9 : result = 3; break; case 10: result = v >= 1000 ? 4 : 3; break; case 11: case 12: case 13: result = 4; break; case 14: result = v >= 1 ? 5 : 4; break; case 15: case 16: result = 5; break; case 17: result = v >= 10 ? 6 : 5; break; case 18: case 19: result = 6; break; case 20: result = v >= 100 ? 7 : 6; break; case 21: case 22: case 23: result = 7; break; case 24: result = v >= 1000 ? 8 : 7; break; case 25: case 26: result = 8; break; case 27: result = v >= 1 ? 9 : 8; break; case 28: case 29: case 30: case 31: case 32: result = 9; break; default: assert(false); } return result; } private ubyte ffdecimalLength9(const uint v) pure nothrow { import core.bitop; const ubyte lzc = cast(ubyte) (bsr(v) + 1); static immutable pure nothrow ubyte function(uint)[33] tbl = [ 0 : (uint a) => ubyte(1), 1 : (uint a) => ubyte(1), 2 : (uint a) => ubyte(1), 3 : (uint a) => ubyte(1), 4 : (uint a) => a >= 10 ? ubyte(2) : ubyte(1), 5 : (uint a) => ubyte(2), 6 : (uint a) => ubyte(2), 7 : (uint a) => a >= 100 ? ubyte(3) : ubyte(2), 8 : (uint a) => ubyte(3), 9 : (uint a) => ubyte(3), 10: (uint a) => a >= 1000 ? ubyte(4) : ubyte(3), 11: (uint a) => ubyte(4), 12: (uint a) => ubyte(4), 13: (uint a) => ubyte(4), 14: (uint a) => a >= 1 ? ubyte(5) : ubyte(4), 15: (uint a) => ubyte(5), 16: (uint a) => ubyte(5), 17: (uint a) => a >= 10 ? ubyte(6) : ubyte(5), 18: (uint a) => ubyte(6), 19: (uint a) => ubyte(6), 20: (uint a) => a >= 100 ? ubyte(7) : ubyte(6), 21: (uint a) => ubyte(7), 22: (uint a) => ubyte(7), 23: (uint a) => ubyte(7), 24: (uint a) => a >= 1000 ? ubyte(8) : ubyte(7), 25: (uint a) => ubyte(8), 26: (uint a) => ubyte(8), 27: (uint a) => a >= 1 ? ubyte(9) : ubyte(8), 28: (uint a) => ubyte(9), 29: (uint a) => ubyte(9), 30: (uint a) => ubyte(9), 31: (uint a) => ubyte(9), 32: (uint a) => ubyte(9), ]; return tbl[lzc](v); } void main() { import std.datetime.stopwatch, std.range, std.algorithm; int s1, s2, s3; benchmark!({ iota(1u).each!(a => s1 += decimalLength9(a+1)); })(10).writeln; benchmark!({ iota(1u).each!(a => s2 += fdecimalLength9(a+1));})(10).writeln; benchmark!({ iota(1u).each!(a => s3 += ffdecimalLength9(a+1));})(10).writeln; assert(s1 == s2); assert(s1 == s3); } --- Then bad surprise. Even with ldmd (so ldc2 basically) feeded with the args from the script line. Maybe the fdecimalLength9 version is slightly faster. Only *slightly*. Good news, I've lost my time. So I try an alternative version that uses a table of delegates instead of a switch (ffdecimalLength9) and surprise, "tada", it is like **100x** slower then the two others. How is that possible ?
Re: Strange counter-performance in an alternative `decimalLength9` function
On Wed, Feb 26, 2020 at 12:50:35AM +, Basile B. via Digitalmars-d-learn wrote: [...] > #!dmd -boundscheck=off -O -release -inline [...] TBH, I'm skeptical of any performance results using dmd. I wouldn't pay attention to performance numbers obtained this way, and rather look at the ldmd/ldc2 numbers. [...] > Then bad surprise. Even with ldmd (so ldc2 basically) feeded with the > args from the script line. Maybe the fdecimalLength9 version is > slightly faster. Only *slightly*. Good news, I've lost my time. So I > try an alternative version that uses a table of delegates instead of a > switch (ffdecimalLength9) and surprise, "tada", it is like **100x** > slower then the two others. > > How is that possible ? Did you check the assembly output to see what the difference is? Delegates involve a function call, which involves function call overhead, which includes a CPU pipeline hazard. Worse yet it's an indirect call, meaning you're defeating the CPU branch predictor and invalidating the instruction cache. And on top of that, delegates involve allocating a context, and you *really* do not want allocations inside an inner loop. And of course, normal function calls are easier for compilers to inline, because the destination is fixed. Indirect calls involving delegates are hard to predict, and the optimizer is more liable to just give up. These are just my educated guesses, of course. For the real answer, look at the assembly output. :-D T -- What are you when you run out of Monet? Baroque.
Re: Strange counter-performance in an alternative `decimalLength9` function
On Wednesday, 26 February 2020 at 01:10:07 UTC, H. S. Teoh wrote: On Wed, Feb 26, 2020 at 12:50:35AM +, Basile B. via Digitalmars-d-learn wrote: [...] #!dmd -boundscheck=off -O -release -inline [...] TBH, I'm skeptical of any performance results using dmd. I wouldn't pay attention to performance numbers obtained this way, and rather look at the ldmd/ldc2 numbers. I didn't use DMD. The script line is actually interpreted by the IDE. It drops the compiler name and just parse the arg and pass them to a compiler that's defined by non overridable options. In my case I used LDMD (this is LDC you see, but with a DMD like options syntax)