Re: Overloading for lvalue and rvalue.
On Monday, June 12, 2017 20:40:52 Balagopal Komarath via Digitalmars-d-learn wrote: > Is there a way to avoid the following combinatorial explosion of > overloaded functions when overloading for lvalue and rvalue > arguments? The following may be a bad example because int is > cheap to copy. So assume a large datatype instead of int. > > import std.stdio; > > void foo(in ref int a, in ref int b) > { > writeln("r, r"); > } > > void foo(in ref int a, in int b) > { > writeln("r, i"); > } > > void foo(in int a, in ref int b) > { > writeln("i, r"); > } > > void foo(in int a, in int b) > { > writeln("i, i"); > } > > void main() > { > int a, b; > foo(a, b); > foo(a, 0); > foo(0, a); > foo(0, 0); > } If you templatize the function, you can use auto ref. e.g. void foo(T)(auto ref T a) {..} or void foo()(auto ref int a) {...} and then when the function is instantiated, the instantiation will be ref or non-ref depending on whether an lvalue or rvalue was passed. So you still get the combinatorial explosion of functions, but you don't have to write them manually. Of course, if you're dealing with a virtual function though, you'll have to do it manually, because templated functions can't be virtual. But in cases like that, you could have a protected function which took ref and a public, templated, wrapper function that took auto ref so that you don't have to do it all manually. In general though, I'd suggest just not using ref to avoid copying unless you know that it's a performance problem. - Jonathan M Davis
Overloading for lvalue and rvalue.
Is there a way to avoid the following combinatorial explosion of overloaded functions when overloading for lvalue and rvalue arguments? The following may be a bad example because int is cheap to copy. So assume a large datatype instead of int. import std.stdio; void foo(in ref int a, in ref int b) { writeln("r, r"); } void foo(in ref int a, in int b) { writeln("r, i"); } void foo(in int a, in ref int b) { writeln("i, r"); } void foo(in int a, in int b) { writeln("i, i"); } void main() { int a, b; foo(a, b); foo(a, 0); foo(0, a); foo(0, 0); }
Re: Generic operator overloading for immutable types?
On Mon, Jun 12, 2017 at 01:08:13PM -0700, Ali Çehreli via Digitalmars-d-learn wrote: > On 06/12/2017 01:03 PM, Gary Willoughby wrote: > > On Monday, 12 June 2017 at 19:36:52 UTC, H. S. Teoh wrote: > > >> public inout Rational opBinary(string op)(inout Rational rhs) > > > Quick question about the signature, if I change it to (note the parens): > > > >public inout(Rational) opBinary(string op)(inout(Rational) rhs) > > > > It no longer works, why is that? > > That's frequently faced issue with D. :) In the first declaration, > inout applies to the member function. More precisely, it applies to the `this` reference implicitly passed to the member function. You need inout to apply to `this`, otherwise a.opBinary(b) won't work when a is an immutable instance. > In the second one, it applies only to the return type. Walter has his > rationale for doing it that way but it's confusing. [...] A few years ago we tried lobbying for the language to enforce putting modifiers that only apply to the function itself on the far right side, e.g.: public Rational opBinary(string op)(inout Rational rhs) inout But it was rejected for various reasons. Therefore, nowadays I always recommend writing parenthesis with type modifiers, so that the intent it unambiguous, i.e., always write `inout(Rational)` rather than `inout Rational`, unless you intend for `inout` to apply to the function rather than the return value. (And I apologize for the slip-up in my code example above, where I failed to do this for the function parameter.) T -- Маленькие детки - маленькие бедки.
Re: Generic operator overloading for immutable types?
On 06/12/2017 01:03 PM, Gary Willoughby wrote: > On Monday, 12 June 2017 at 19:36:52 UTC, H. S. Teoh wrote: >> public inout Rational opBinary(string op)(inout Rational rhs) > Quick question about the signature, if I change it to (note the parens): > >public inout(Rational) opBinary(string op)(inout(Rational) rhs) > > It no longer works, why is that? That's frequently faced issue with D. :) In the first declaration, inout applies to the member function. In the second one, it applies only to the return type. Walter has his rationale for doing it that way but it's confusing. Ali
Re: Generic operator overloading for immutable types?
On Monday, 12 June 2017 at 19:36:52 UTC, H. S. Teoh wrote: On Mon, Jun 12, 2017 at 07:38:44PM +, Gary Willoughby via Digitalmars-d-learn wrote: In the following code is there any way to make the `opBinary` method generic to be able to accept immutable as well as a standard type? The code currently passes the unit test but I wonder if I could get rid of the duplication to overload the operator? I'm failing badly. This is what inout was designed for: public inout Rational opBinary(string op)(inout Rational rhs) { static if (op == "+") { return inout(Rational)(0, 0); } else { static assert(0, "Operator '" ~ op ~ "' not implemented"); } } That should do the trick. T Quick question about the signature, if I change it to (note the parens): public inout(Rational) opBinary(string op)(inout(Rational) rhs) It no longer works, why is that?
Re: Generic operator overloading for immutable types?
On Monday, 12 June 2017 at 19:51:37 UTC, Gary Willoughby wrote: I don't know how H. S. Teoh managed to answer 'before' I posted but thanks guys! :) might be a bug, happened here http://forum.dlang.org/post/ohbr5l$2mng$1...@digitalmars.com also.
Re: Generic operator overloading for immutable types?
I don't know how H. S. Teoh managed to answer 'before' I posted but thanks guys! :)
Re: Weird template instantiation problem
Arafel wrote: I actually found a workaround for the original issue: yeah, sorry for not proposing a workaround: i thought that you already did it, and now you're just interested why the original code doesn't work. ;-) i think that this is a bug (or, rather, unimplemented feature).
Re: Generic operator overloading for immutable types?
Gary Willoughby wrote: In the following code is there any way to make the `opBinary` method generic to be able to accept immutable as well as a standard type? The code currently passes the unit test but I wonder if I could get rid of the duplication to overload the operator? I'm failing badly. public inout(Rational) opBinary(string op)(inout(Rational) rhs) inout { static if (op == "+") { return Rational(0, 0); } else { static assert(0, "Operator '" ~ op ~ "' not implemented"); } }
Re: Generic operator overloading for immutable types?
On Mon, Jun 12, 2017 at 07:38:44PM +, Gary Willoughby via Digitalmars-d-learn wrote: > In the following code is there any way to make the `opBinary` method > generic to be able to accept immutable as well as a standard type? The > code currently passes the unit test but I wonder if I could get rid of > the duplication to overload the operator? I'm failing badly. This is what inout was designed for: public inout Rational opBinary(string op)(inout Rational rhs) { static if (op == "+") { return inout(Rational)(0, 0); } else { static assert(0, "Operator '" ~ op ~ "' not implemented"); } } That should do the trick. T -- Frank disagreement binds closer than feigned agreement.
Re: Weird template instantiation problem
On Monday, 12 June 2017 at 19:23:10 UTC, ketmar wrote: p.s.: while i understand the technical reason for second error message, it is still random and confusing. I think the reason for the typeof problem is that it works with expressions, not with types (so, typeof (int) is also not valid), and the alias resolves ultimately to a type. I actually found a workaround for the original issue: ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, alias chooser = defaultChooser!int) if (is(typeof(chooser) : size_t function(T[]))) { } void main() { S!(int, defaultChooser!int) s; } ``` This works, but strangely if I try "==" instead of ":" in the template condition, then it fails again. Honestly I don't know why it makes a difference, I guess attribute inference might be at fault... but in the version with the "static assert" I was explicitly checking them, and they apparently matched... Also, this is just a(n ugly) workaround, and there might be side effects of using an alias parameter that I'm not aware of... and more importantly, I still think the original version should work! ;-)
Generic operator overloading for immutable types?
In the following code is there any way to make the `opBinary` method generic to be able to accept immutable as well as a standard type? The code currently passes the unit test but I wonder if I could get rid of the duplication to overload the operator? I'm failing badly. import std.stdio; struct Rational { public long numerator; public long denominator; public immutable Rational opBinary(string op)(immutable Rational rhs) { static if (op == "+") { return Rational(0, 0); } else { static assert(0, "Operator '" ~ op ~ "' not implemented"); } } public Rational opBinary(string op)(Rational rhs) { static if (op == "+") { return Rational(0, 0); } else { static assert(0, "Operator '" ~ op ~ "' not implemented"); } } } unittest { auto foo = Rational(1, 3); auto bar = Rational(1, 6); writefln("%s", foo + bar); auto baz = immutable Rational(1, 3); auto qux = immutable Rational(1, 6); writefln("%s", baz + qux); }
Re: Weird template instantiation problem
p.s.: while i understand the technical reason for second error message, it is still random and confusing.
Re: Weird template instantiation problem
more funny compiler messages: alias xx = size_t function (int[]); struct S1(T, typeof(xx) X) {} void main() { S1!(int, defaultChooser!int) s; } Error: type uint function(int[]) is not an expression but: struct S2(T, typeof(defaultChooser!T) chooser=defaultChooser!T) {} void main() { S2!int s; } Error: undefined identifier T error messages are totally random (and why `typeof()` is not allowed there?)
Re: O(1) sum
On Mon, Jun 12, 2017 at 06:16:06PM +, Stefan Koch via Digitalmars-d-learn wrote: > On Monday, 12 June 2017 at 06:15:07 UTC, Biotronic wrote: [...] > > On a multi-core system we can do better: > > > > auto nums = iota(10_000_000.0f); > > auto sum = taskPool.reduce!"a + b"(nums); > > > > Given arbitrary parallelism (yeah, right!), this will be O(log(N)). > > For real-world systems, it might give a speed-up for large arrays, > > but won't reduce the big-O complexity. Of course, there will also be > > overhead to such a solution, so there is a limit to how much one'd > > actually benefit from it. > > > > -- > > Biotronic > > Biotronic how do you arrive at O(log(N)) ?? > And which logarithm ? His stated presupposition is arbitrary parallelism, which I assume means arbitrary number of CPUs or cores that can run in parallel, so then you can divide the array of N elements into N/2 pairs, sum each pair in parallel, which gives you N/2 subtotals after one iteration, then you recursively repeat this on the subtotals until you're left with the final total. The complexity would be O(log_2(N)) iterations, assuming that the constant factor hidden by the big-O covers the overhead of managing the parallel summing operations across the arbitrary number of cores. You can also get logarithms of a different base if you divided the initial array, say, into triplets or j-tuplets, for some constant j. Then you'd get O(log_j(N)). (Of course, with a slightly larger constant factor, assuming that each CPU core only has binary summation instructions. But if your instruction set has multiple-summation instructions you may be able to get a higher j at little or no additional cost. Assuming you can produce a machine with an unlimited number of cores in the first place.) Of course, his comment "yeah, right!" indicates that he's aware that this is an unrealistic scenario. :-) T -- Notwithstanding the eloquent discontent that you have just respectfully expressed at length against my verbal capabilities, I am afraid that I must unfortunately bring it to your attention that I am, in fact, NOT verbose.
Re: O(1) sum
On 06/11/2017 06:02 PM, helxi wrote: Is it possible to sum an array in O(1)? It's possible to maintain the sum as elements are added and removed. Then, accessing it would be O(1). Ali
Re: O(1) sum
On Monday, 12 June 2017 at 06:15:07 UTC, Biotronic wrote: On Monday, 12 June 2017 at 01:36:04 UTC, Stefan Koch wrote: On Monday, 12 June 2017 at 01:02:58 UTC, helxi wrote: Is it possible to sum an array in O(1)? No. If you want to sum the elements you have to at-least look at all the elements. So it'll always be O(N). it's the best you can do. On a multi-core system we can do better: auto nums = iota(10_000_000.0f); auto sum = taskPool.reduce!"a + b"(nums); Given arbitrary parallelism (yeah, right!), this will be O(log(N)). For real-world systems, it might give a speed-up for large arrays, but won't reduce the big-O complexity. Of course, there will also be overhead to such a solution, so there is a limit to how much one'd actually benefit from it. -- Biotronic Biotronic how do you arrive at O(log(N)) ?? And which logarithm ?
Re: Weird template instantiation problem
On 06/12/2017 05:31 PM, Arafel wrote: Hi, I've found a strange problem, and I'm not sure if it's a bug. To give a bit of background, I'm implementing a multi-threaded producer-consumer where the next work item to be picked depends not only on the "waiting queue", but also on what else is being run (and potentially where) at the same moment, so things like "sort"'ing the queue won't probably work, because I don't think you use a delegate as a predicate for "sort" (that's what I think it would be needed to get the extra context information). The idea here is that the "chooser" function returns the *index* of the work item to be picked. So, the reduced problem looks like this (I've removed the extra information about the running jobs to make the example simpler): ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, size_t function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` this fails and I get this: Error: template instance S!int does not match template declaration S(T, ulong function(T[]) chooser = defaultChooser!T) If instead of returning the index the actual item is returned, it works! ``` enum defaultChooser(T) = function T(T[] queue) { return queue[0]; }; struct S(T, T function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` As you can see, the only change is the type the function returns, but I don't see how it should make any difference. Also, changing from "enum" to "static immutable", or even removing the "enum" and directly embedding the function literal doesn't seem to make any difference. Any ideas on what might be going on?? Even more strange: ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; static assert (is (typeof(defaultChooser!int) == size_t function(int[] queue) pure nothrow @nogc @safe)); struct S(T, size_t function(T[] queue) pure nothrow @nogc @safe chooser) { } void main() { S!(int, defaultChooser!int) s; } ``` The static assert passes (tried with the wrong values), yet I get this error message: Error: template instance S!(int, function ulong(int[] queue) => 0LU) does not match template declaration S(T, ulong function(T[] queue) pure nothrow @nogc @safe chooser) Am I missing something fundamental? But then, why does it work if I change the return type in the template parameter?
Weird template instantiation problem
Hi, I've found a strange problem, and I'm not sure if it's a bug. To give a bit of background, I'm implementing a multi-threaded producer-consumer where the next work item to be picked depends not only on the "waiting queue", but also on what else is being run (and potentially where) at the same moment, so things like "sort"'ing the queue won't probably work, because I don't think you use a delegate as a predicate for "sort" (that's what I think it would be needed to get the extra context information). The idea here is that the "chooser" function returns the *index* of the work item to be picked. So, the reduced problem looks like this (I've removed the extra information about the running jobs to make the example simpler): ``` enum defaultChooser(T) = function size_t(T[] queue) { return 0; }; struct S(T, size_t function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` this fails and I get this: Error: template instance S!int does not match template declaration S(T, ulong function(T[]) chooser = defaultChooser!T) If instead of returning the index the actual item is returned, it works! ``` enum defaultChooser(T) = function T(T[] queue) { return queue[0]; }; struct S(T, T function(T[]) chooser = defaultChooser!T) { } void main() { S!int s; } ``` As you can see, the only change is the type the function returns, but I don't see how it should make any difference. Also, changing from "enum" to "static immutable", or even removing the "enum" and directly embedding the function literal doesn't seem to make any difference. Any ideas on what might be going on??
Trouble with regex backreferencing
I was working around with regex trying to match certain patterns of repeating patterns before and after a space and I came across some unexpected behavior. writeln("ABC ABC CBA".replaceAll(regex(r"([A-Z]) ([A-Z])"), "D")); //ABDBDBA //Makes sense, replaces the 3 characters surrounding a space with a single D writeln("ABC ABC CBA".replaceAll(regex(r"([A-Z]) \1"), "D")); //ABC ABDBA //Same idea, but this time only if the 2 surrounding letters are the same writeln("ABC ABC CBA".replaceAll(regex(r"([A-Z]+) \1"), "D")); //D CBA //Same idea again, but this time match any amount of characters as long as they are in the same order writeln("ABCABC ABC CBA".replaceAll(regex(r"([A-Z]+) \1"), "D")); //ABCABC ABC CBA //Hold on, shouldn't this be "ABCD CBA"? writeln("ABC ABCABC CBA".replaceAll(regex(r"([A-Z]+) \1"), "D")); //DABC CBA //Works the other way The problem I've come across is that the regex should be matching the largest portion of the subexpression that it can for both the first usage, but it is matching the most it can for its first reference without any care as to its future usage, making it only work if the entirety of the first word is contained at the start of the second, where it should work both ways. Is there any gross hack I can do to get around this and if this is for some reason intended behavior, why?
Re: std.path.buildPath
On Sun, 2017-06-04 at 21:32 +0200, Jacob Carlborg via Digitalmars-d- learn wrote: > On 2017-06-04 19:05, Patrick Schluter wrote: > > > buildPath("/usr/bin", "/usr/bin/gcc") > > > > /usr/bin/usr/bin/gcc is obviously wrong. > > Says who? It might be exactly what I want. The case that came up is > inside DStep. The user provides a set of files C header to be > translated > to D modules. The user also provides a flag to indicate where to > place > the resulting files. I wanted to be able to keep the existing > directory > structure of the header files in the new target location. Example: Says Guido et al. it seems, Python has in os.path and pathlib exactly this behaviour. > dstep -o result /usr/include/libxml2/libxml/*.h > > The internals of DStep will do something like: > > buildPath("result", "/usr/include/libxml2/libxml"); > > Which currently results in "/usr/include/libxml2/libxml". The end > result > is that DStep will try to write a file to > "/usr/include/libxml2/libxml", > which the user most likely will not have access to (without using > sudo). > I expected the result of buildPath to be > "result/usr/include/libxml2/libxml". Sadly Python tells us otherwise just as D does. It is perhaps worth noting in passing that D path support seems very like os.path and Python folk are giving that up in favour of pathlib. Java/Kotlin/Groovy have also gone the same way. The implication is that D needs better path support than it currently has to keep up with the evolutions in other languages. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: std.path.buildPath
On Sun, 2017-06-11 at 13:21 +, Ryan Frame via Digitalmars-d-learn wrote: > On Sunday, 4 June 2017 at 18:15:36 UTC, Russel Winder wrote: > > On Sun, 2017-06-04 at 17:56 +0200, Jacob Carlborg via > > Digitalmars-d- learn wrote: > > > On 2017-06-04 07:44, Jesse Phillips wrote: > > > > > > > What is your expected behavior? Throw an exception? You can't > > > > really > > > > append an absolute path to another. > > > > > > Of course you can. I expect buildPath("/foo", "/bar") to > > > result in "/foo/bar". That's how Ruby behaves. > > > > And Python, Groovy, Java, Kotlin, Ceylon, C++, … > > Python 3.5.1 on my machine: > > >>> os.path.join("/asdf", "/bcd") > '/bcd' > >>> os.path.join("asdf", "/bcd") > '/bcd' ### you are absolutely right, and it is clearly stated in the documentation that this is the expected behaviour. Clearly, I have never tried doing that in 20 years of playing with Python. And it has never come up in 12 years of running Python workshops! This behaviour is reinforced by pathlib which is the modern way of doing paths in Python, replacing os.path: import pathlib p = pathlib.Path() p = p.joinpath('/', 'usr', '/local', '/bin') print(p) result /bin. So given Python is one of the targets for D, consistency of behaviour implies D is currently doing the right thing. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part