Re: Overloading for lvalue and rvalue.

2017-06-12 Thread Jonathan M Davis via Digitalmars-d-learn
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.

2017-06-12 Thread Balagopal Komarath via Digitalmars-d-learn
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?

2017-06-12 Thread H. S. Teoh via Digitalmars-d-learn
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?

2017-06-12 Thread Ali Çehreli via Digitalmars-d-learn

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?

2017-06-12 Thread Gary Willoughby via Digitalmars-d-learn

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?

2017-06-12 Thread arturg via Digitalmars-d-learn

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?

2017-06-12 Thread Gary Willoughby via Digitalmars-d-learn
I don't know how H. S. Teoh managed to answer 'before' I posted 
but thanks guys! :)


Re: Weird template instantiation problem

2017-06-12 Thread ketmar via Digitalmars-d-learn

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?

2017-06-12 Thread ketmar via Digitalmars-d-learn

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?

2017-06-12 Thread H. S. Teoh via Digitalmars-d-learn
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

2017-06-12 Thread Arafel via Digitalmars-d-learn

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?

2017-06-12 Thread Gary Willoughby via Digitalmars-d-learn
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

2017-06-12 Thread ketmar via Digitalmars-d-learn
p.s.: while i understand the technical reason for second error message, it 
is still random and confusing.


Re: Weird template instantiation problem

2017-06-12 Thread ketmar via Digitalmars-d-learn

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

2017-06-12 Thread H. S. Teoh via Digitalmars-d-learn
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

2017-06-12 Thread Ali Çehreli via Digitalmars-d-learn

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

2017-06-12 Thread Stefan Koch via Digitalmars-d-learn

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

2017-06-12 Thread Arafel via Digitalmars-d-learn

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

2017-06-12 Thread Arafel via Digitalmars-d-learn

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

2017-06-12 Thread Murp via Digitalmars-d-learn
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

2017-06-12 Thread Russel Winder via Digitalmars-d-learn
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

2017-06-12 Thread Russel Winder via Digitalmars-d-learn
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