Re: Operator "+=" overloading for class?

2023-12-20 Thread Ki Rill via Digitalmars-d-learn
On Wednesday, 20 December 2023 at 02:56:24 UTC, Steven 
Schveighoffer wrote:
Instead you are trying to reassign the `this` reference, which 
is a local (and also forbidden). Think about it a second, your 
`this + rhs` is going to allocate a *new* object. Then if the 
assignment to the local `this` parameter succeeded, what 
happens outside the member function? The true reference that is 
calling this will not be updated!


The only way to do this I can see is to reimplement for op=, or 
maybe perform the operation and swap the guts out.


-Steve


Thank you for such a detailed explanation! That does make sense.


Re: Operator "+=" overloading for class?

2023-12-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On Monday, 18 December 2023 at 14:38:14 UTC, Ki Rill wrote:

your code just return result value,
but it should not return but save result to "this"
see example at 
https://dlang.org/spec/operatoroverloading.html#index_op_assignment


I get an error, but don't understand why.
```d
auto opOpAssign(string op)(Value rhs)
{
this = this + rhs;
return this;
}

// Error: `this` is not an lvalue and cannot be modified
```


Assigning an object is like copying a pointer. You may think you 
can try overloading the assignment, but it is 
[forbidden](https://dlang.org/spec/operatoroverloading.html#assignment):


```
However for class types, identity assignment is not allowed. All 
class types have reference semantics, so identity assignment by 
default rebinds the left-hand-side to the argument at the right, 
and this is not overridable.

```

But you aren't trying to do this.

Instead you are trying to reassign the `this` reference, which is 
a local (and also forbidden). Think about it a second, your `this 
+ rhs` is going to allocate a *new* object. Then if the 
assignment to the local `this` parameter succeeded, what happens 
outside the member function? The true reference that is calling 
this will not be updated!


The only way to do this I can see is to reimplement for op=, or 
maybe perform the operation and swap the guts out.


-Steve


Re: Operator "+=" overloading for class?

2023-12-18 Thread Alexandru Ermicioi via Digitalmars-d-learn

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:
I am trying to overload `opOpAssign` for my class. The code 
compiles, but it does not seem to be working.


```d
// binary operations have already been implemented for Value
// i need +=, -=, *=, /=
auto opOpAssign(string op)(Value rhs)
{
mixin("return this" ~ op ~ "rhs;");
}

auto opOpAssign(string op)(in ElementType rhs)
{
mixin("return this" ~ op ~ "rhs;");
}
```

What am I missing here? Full project code can be found 
[here](https://github.com/rillki/tiny-grad).


Perhaps:
```d
auto opOpAssign(string op)(Value other) {
mixin("this.v " ~ op ~ "= other.v;");
return this;
}
```


Re: Operator "+=" overloading for class?

2023-12-18 Thread Ki Rill via Digitalmars-d-learn

On Monday, 18 December 2023 at 04:49:53 UTC, novice2 wrote:

On Monday, 18 December 2023 at 03:39:16 UTC, Ki Rill wrote:
On Sunday, 17 December 2023 at 07:05:12 UTC, Adam D. Ruppe 
wrote:

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:

[...]


check what `op` is. pretty sure it is "+" not "+=" so your 
element isnt' saved anywhere. also a bit iffy there isn't a 
member here to work on


Yes, op is '+'. What do you mean by it isn't saved anywhere?


your code just return result value,
but it should not return but save result to "this"
see example at 
https://dlang.org/spec/operatoroverloading.html#index_op_assignment


I get an error, but don't understand why.
```d
auto opOpAssign(string op)(Value rhs)
{
this = this + rhs;
return this;
}

// Error: `this` is not an lvalue and cannot be modified
```


Re: Operator "+=" overloading for class?

2023-12-17 Thread novice2 via Digitalmars-d-learn

On Monday, 18 December 2023 at 03:39:16 UTC, Ki Rill wrote:
On Sunday, 17 December 2023 at 07:05:12 UTC, Adam D. Ruppe 
wrote:

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:

[...]


check what `op` is. pretty sure it is "+" not "+=" so your 
element isnt' saved anywhere. also a bit iffy there isn't a 
member here to work on


Yes, op is '+'. What do you mean by it isn't saved anywhere?


your code just return result value,
but it should not return but save result to "this"
see example at 
https://dlang.org/spec/operatoroverloading.html#index_op_assignment





Re: Operator "+=" overloading for class?

2023-12-17 Thread Ki Rill via Digitalmars-d-learn

On Sunday, 17 December 2023 at 07:05:12 UTC, Adam D. Ruppe wrote:

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:

[...]


check what `op` is. pretty sure it is "+" not "+=" so your 
element isnt' saved anywhere. also a bit iffy there isn't a 
member here to work on


Yes, op is '+'. What do you mean by it isn't saved anywhere? I 
tried reassigning to `this` and returning it, but it fails.


I want to achieve this, but with '+=':
```d
auto g = value(0);
g = g + value(3);

// here it should just create a new instance 'g + value(3)' and 
save it into 'g'

g += value(3);
```

Do you have an advice on how to achieve it?


Re: Operator "+=" overloading for class?

2023-12-16 Thread Adam D. Ruppe via Digitalmars-d-learn

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:

auto opOpAssign(string op)(in ElementType rhs)
{
mixin("return this" ~ op ~ "rhs;");
}
```


check what `op` is. pretty sure it is "+" not "+=" so your 
element isnt' saved anywhere. also a bit iffy there isn't a 
member here to work on


Re: Operator "+=" overloading for class?

2023-12-16 Thread Ki Rill via Digitalmars-d-learn

On Sunday, 17 December 2023 at 04:15:02 UTC, Ki Rill wrote:

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:
I am trying to overload `opOpAssign` for my class. The code 
[...]




I forgot to mention, it is relevant to 
[`Value`](https://github.com/rillki/tiny-grad/blob/main/source/rk/tgrad/core/value.d) class only.


This unittest fails:
```d
// test opOpAssign
auto g = value(0);
g += value(3);
assert(g.data == 3);
```


Re: Operator "+=" overloading for class?

2023-12-16 Thread Ki Rill via Digitalmars-d-learn

On Sunday, 17 December 2023 at 04:13:20 UTC, Ki Rill wrote:
I am trying to overload `opOpAssign` for my class. The code 
[...]




I forgot to mention, it is relevant to 
[`Value`](https://github.com/rillki/tiny-grad/blob/main/source/rk/tgrad/core/value.d) class only.


Operator "+=" overloading for class?

2023-12-16 Thread Ki Rill via Digitalmars-d-learn
I am trying to overload `opOpAssign` for my class. The code 
compiles, but it does not seem to be working.


```d
// binary operations have already been implemented for Value
// i need +=, -=, *=, /=
auto opOpAssign(string op)(Value rhs)
{
mixin("return this" ~ op ~ "rhs;");
}

auto opOpAssign(string op)(in ElementType rhs)
{
mixin("return this" ~ op ~ "rhs;");
}
```

What am I missing here? Full project code can be found 
[here](https://github.com/rillki/tiny-grad).


Re: Operator Overloading for Enum

2021-02-08 Thread DolphinChips via Digitalmars-d-learn

On Monday, 8 February 2021 at 15:56:24 UTC, Michael Brown wrote:

Hi all,

Is it possible to operator overload on enums? I'd like to do a 
opCmp()


Kind regards,
Mike


You can create custom struct type with opCmp() and create enum 
with that type. Example: https://run.dlang.io/is/m7DN66


Operator Overloading for Enum

2021-02-08 Thread Michael Brown via Digitalmars-d-learn

Hi all,

Is it possible to operator overload on enums? I'd like to do a 
opCmp()


Kind regards,
Mike


Re: Operator Overloading for Enum

2021-02-08 Thread Paul Backus via Digitalmars-d-learn

On Monday, 8 February 2021 at 15:56:24 UTC, Michael Brown wrote:

Hi all,

Is it possible to operator overload on enums? I'd like to do a 
opCmp()


Kind regards,
Mike


No, it isn't. Only structs and classes can have overloaded 
operators.


Re: opCast / operator overloading with additional template arguments

2021-01-11 Thread Ali Çehreli via Digitalmars-d-learn

On 1/10/21 7:27 PM, Paul wrote:

> On Monday, 11 January 2021 at 02:37:24 UTC, Ali Çehreli wrote:
>> >> T opCast(T)() const if (is(T : Vec!(size, S2), S2)) {
>
>> The is expression can be so complicated that I used a different
>> approach below.
>
>>   if (isInstanceOfVec!T &&
>>   T.init.content.length == size) {
>> // ADDED:
>> alias S2 = typeof(T.init.content[0]);
>
> Is it ok to use .init even though we don't need an instantiated value?

Yes, .init useful in many templates. However, you don't actually use 
that object because typeof does not evaluate the expression, just 
produces the type of it.


Related, the content[0] expression might be seen as invalid code because 
the array may not have any elements at all but again, there is no access 
to element 0. There are other ways e.g.


import std.range;
alias S2 = ElementType!(typeof(T.init.content));

Ali




Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Paul Backus via Digitalmars-d-learn

On Monday, 11 January 2021 at 03:40:41 UTC, Paul wrote:
On Monday, 11 January 2021 at 00:48:49 UTC, Steven 
Schveighoffer wrote:

I would think though, that this should work:

T opCast(T : Vec!(vecsize, S), S)()


Oh wouw, this seems to work perfectly! Awesome thanks ^^

Any Idea why

T opCast(T, S)() const if (is(T : Vec!(grootte, S))) {

yields the error
template instance opCast!(Vec!(2, double)) does not match 
template declaration opCast(T, S)()
while your suggestion does not? It seems to me it should match 
equally well.


The compiler does not look at template constraints until after it 
figures out what all the template arguments are. So, in your 
version, it sees


T opCast(T, S) // ...
opCast!(Vec!(2, double))

...and is able to deduce that `T = Vec!(2, double)`, but doesn't 
have any way to figure out what `S` is, so it gives up.


Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Paul via Digitalmars-d-learn
On Monday, 11 January 2021 at 00:48:49 UTC, Steven Schveighoffer 
wrote:

I would think though, that this should work:

T opCast(T : Vec!(vecsize, S), S)()


Oh wouw, this seems to work perfectly! Awesome thanks ^^

Any Idea why

T opCast(T, S)() const if (is(T : Vec!(grootte, S))) {

yields the error
template instance opCast!(Vec!(2, double)) does not match 
template declaration opCast(T, S)()
while your suggestion does not? It seems to me it should match 
equally well.


Also I had no clue types inferred in constraints were 
inaccessibly, I'll try to keep that in mind, though I wonder, is 
there is any specific reason for that? Then again since your 
example works inferred values shouldnt be necessary in 
constraints anyway.
(On that note, is there per chance something like the underscore 
'_' as in python? In some cases I don't care for all the template 
arguments inside an is expression (with the (a:b, c) version))


Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Paul via Digitalmars-d-learn

On Monday, 11 January 2021 at 02:37:24 UTC, Ali Çehreli wrote:

>> T opCast(T)() const if (is(T : Vec!(size, S2), S2)) {


The is expression can be so complicated that I used a different 
approach below.



  if (isInstanceOfVec!T &&
  T.init.content.length == size) {
// ADDED:
alias S2 = typeof(T.init.content[0]);


Is it ok to use .init even though we don't need an instantiated 
value?


Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Ali Çehreli via Digitalmars-d-learn

On 1/10/21 6:37 PM, Ali Çehreli wrote:

>// OBSERVATION: Should the cast below be S?
>converted.content[i] = cast(S2) content[i];

I take that back. Yes, it should be S2. (I've been off lately. :) )

Ali




Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Ali Çehreli via Digitalmars-d-learn

On 1/10/21 5:09 PM, Paul wrote:

> I'll paste more of my file, I hope that's ok.

Not only ok but much appreciated. :)

>> T opCast(T)() const if (is(T : Vec!(size, S2), S2)) {

The is expression can be so complicated that I used a different approach 
below. I left notes in capital letters below. Especially cast(S2) looks 
wrong to me:


import std;

version (HoekjeD_Double) {
  private alias standard_accuracy = double;
} else {
  private alias standard_accuracy = float;
}

struct Vec(int size, S = standard_accuracy) {
  // You could add this instead of getting the type from
  // 'content' as in how S2 is aliased in opCast below:
  //
  // alias AccuracyType = S;

  union {
S[size] content;
static if (size >= 1) {
  struct {
S x;
static if (size >= 2) {
  S y;
  static if (size >= 3) {
S z;
static if (size >= 4)
  S w;
  }
}
  }
}
  }

  T opCast(T)() const
  // CHANGED:
  if (isInstanceOfVec!T &&
  T.init.content.length == size) {
// ADDED:
alias S2 = typeof(T.init.content[0]);
T converted;
static foreach (i; 0 .. size)
  // OBSERVATION: Should the cast below be S?
  converted.content[i] = cast(S2) content[i];
return converted;
  }
}

enum isInstanceOfVec(T) = isInstanceOf!(Vec, T);

void main() {
  auto a = Vec!(42, float)();
  auto b = a.to!(Vec!(42, double));
}

Ali



Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Paul via Digitalmars-d-learn

On Monday, 11 January 2021 at 00:25:36 UTC, Ali Çehreli wrote:
You don't show complete code; so, I hope I came up with 
something that reflects your case.


Thank you, sadly S (S2 now) is not any specific type, sorry I'll 
paste more of my file, I hope that's ok. (Sidenote, I'm not sure 
it's the most elegant approach to have a templated union like 
this, and I left out some unnecessary stuff like 'opBinary')



version (HoekjeD_Double) {
private alias standard_accuracy = double;
} else {
private alias standard_accuracy = float;
}

struct Vec(int size, S = standard_accuracy) {
union {
S[size] content;
static if (size >= 1) {
struct {
S x;
static if (size >= 2) {
S y;
static if (size >= 3) {
S z;
static if (size >= 4)
S w;
}
}
}
}
}

T opCast(T)() const if (is(T : Vec!(size, S2), S2)) {
T converted;
static foreach (i; 0 .. size)
converted.content[i] = cast(S2) content[i];
return converted;
}
}


Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Steven Schveighoffer via Digitalmars-d-learn

On 1/10/21 7:09 PM, Paul wrote:

Is there a way to have additional template arguments in operator overloads?
The problem I'm having is mostly caused by casting a templated struct to 
other templated structs. I had the following code;



T opCast(T)() const if (is(T : Vec!(vecsize, S), S)) {
T converted;
static foreach (i; 0 .. vecsize)
    converted.content[i] = cast(S) content[i];
return converted;
}


When I try to use this, I get the error 'undefined identifier S'.
Alternatively using:

T opCast(T, S)() . . .
causes the error 'template instance opCast!(Vec!(2, double)) does not 
match template declaration opCast(T, S)()'


I found using 'alias S = typeof(content[0])' works as a kind of ducttape 
alternative, however this seems like a codesmell to me, and I fear it 
won't scale well either.


Am I missing a simple solution? And why is there no automatic argument 
deduction in this scenario when compared to normal function calls? (if 
the above opcast is translated to 'foo.opCast!T`)


It has nothing to do with operator overloads. types inferred inside 
template constraints are not accessible inside the function.


The awkward solution is to use the same is expression inside the function:

static if(is(T : Vec!(vecsize, S), S)) {}

// now you can use S

I would think though, that this should work:

T opCast(T : Vec!(vecsize, S), S)()

But I don't have your full code to test.

-Steve


Re: opCast / operator overloading with additional template arguments

2021-01-10 Thread Ali Çehreli via Digitalmars-d-learn

On 1/10/21 4:09 PM, Paul wrote:

> Is there a way to have additional template arguments in operator 
overloads?


I haven't tried that but the following method seems to work for you. You 
don't show complete code; so, I hope I came up with something that 
reflects your case.


import std;

struct S(T) {
  auto opCast(U)() const
  if (isInstanceOfS!U) {
writefln!"Converting from %s to %s"(S.stringof, U.stringof);
return U.init;
  }
}

enum isInstanceOfS(T) = isInstanceOf!(S, T);

void main() {
  auto a = S!int();
  auto b = cast(S!double)a;  // Works
  auto c = a.to!(S!double);  // This works too
}

I needed the isInstanceOfS wrapper over std.traits.isInstanceOf because 
I could not use isInstanceOf inside the definition of S because the 
symbol 'S' does not mean "the template S", but the specific 
instantiation of it e.g. S!int. Outside, S means "the template S".


Ali



opCast / operator overloading with additional template arguments

2021-01-10 Thread Paul via Digitalmars-d-learn
Is there a way to have additional template arguments in operator 
overloads?
The problem I'm having is mostly caused by casting a templated 
struct to other templated structs. I had the following code;



T opCast(T)() const if (is(T : Vec!(vecsize, S), S)) {
T converted;
static foreach (i; 0 .. vecsize)
converted.content[i] = cast(S) content[i];
return converted;
}


When I try to use this, I get the error 'undefined identifier S'.
Alternatively using:

T opCast(T, S)() . . .
causes the error 'template instance opCast!(Vec!(2, double)) does 
not match template declaration opCast(T, S)()'


I found using 'alias S = typeof(content[0])' works as a kind of 
ducttape alternative, however this seems like a codesmell to me, 
and I fear it won't scale well either.


Am I missing a simple solution? And why is there no automatic 
argument deduction in this scenario when compared to normal 
function calls? (if the above opcast is translated to 
'foo.opCast!T`)


Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Paul Backus via Digitalmars-d-learn
On Saturday, 12 December 2020 at 20:25:48 UTC, Adam D. Ruppe 
wrote:
On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus 
wrote:
IMO this is one of the stupider design decisions in D, but 
it's unlikely it will ever be fixed.


It is useful in several other contexts though, including user 
overriding and private data stores for the mixin.


Sure, but you can always opt in to that behavior by giving the 
mixin a name. The fact that you can't opt out of it even if you 
want to is the issue.


It's essentially the same flaw Andrei criticized C++'s `if 
constexpr` for [1].


[1] https://www.youtube.com/watch?v=tcyb1lpEHm0&t=45m20s


Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Adam D. Ruppe via Digitalmars-d-learn

On Saturday, 12 December 2020 at 20:26:00 UTC, Dennis wrote:

If issue 19365 got fixed


eeek I thought that was fixed but apparently not :(

so yeah alias won't work for operator overloads. Does work for 
other functions so good technique to know but not here.


So for op prolly go with the string mixin


Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Adam D. Ruppe via Digitalmars-d-learn

On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
IMO this is one of the stupider design decisions in D, but it's 
unlikely it will ever be fixed.


It is useful in several other contexts though, including user 
overriding and private data stores for the mixin.


The easiest workaround is to use string mixins instead, which 
work the way you'd expect them to.


But yeah. The other alternative is to alias them together:

class A {
   mixin Whatever a; // need to give it a name here to reference 
later

   mixin Whatever b;

   // explicitly merge overloads here
   alias opBinary = a.opBinary;
   alias opBinary = b.opBinary;
}


Or you can do a forwarder function yourself but that's getting 
even more a hassle. Sometimes appropriate though.


Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Dennis via Digitalmars-d-learn

On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
IMO this is one of the stupider design decisions in D, but it's 
unlikely it will ever be fixed. The easiest workaround is to 
use string mixins instead, which work the way you'd expect them 
to.


If issue 19365 got fixed, it could be done with an alias instead.
https://issues.dlang.org/show_bug.cgi?id=19365

Currently string mixins are indeed the best option though.


Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Tobias Pankrath via Digitalmars-d-learn

On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
Functions from different mixin templates can't overload each 
other. The reason for this is that, when you mix in a mixin 
template, it does not *actually* add the declarations inside it 
to a current scope: instead, it adds them to a new scope, and 
then (essentially) "imports" them into the current scope.

Much appreciated! Exactly the explanation I needed.




Re: Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Paul Backus via Digitalmars-d-learn
On Saturday, 12 December 2020 at 17:36:57 UTC, Tobias Pankrath 
wrote:
I want to wrap e.g. an int and implement basic arithmetic. In 
the provided example [1] I use  two mixin templates to 
separately implement scaling (multiplication with int/double) 
and addition and subtraction with the type itself.


In the end I want to have several distinct wrappers and allow 
specific operations between them and int / double. It's 
important that the return values are typed correctly, otherwise 
I could use std.typecons.Proxy.


My problem is that both overloads of opBinary work, but not at 
the same time. As soon as I mixin both templates, they stop to 
work. If I just paste the implementation into the body of 
WrapInt, they work both at the same time though.


Could someone explain the mechanics behind it?

Thanks!

[1] https://run.dlang.io/is/WbG987


Functions from different mixin templates can't overload each 
other. The reason for this is that, when you mix in a mixin 
template, it does not *actually* add the declarations inside it 
to a current scope: instead, it adds them to a new scope, and 
then (essentially) "imports" them into the current scope.


IMO this is one of the stupider design decisions in D, but it's 
unlikely it will ever be fixed. The easiest workaround is to use 
string mixins instead, which work the way you'd expect them to.


Using multiple mixin templates to implement operator overloading

2020-12-12 Thread Tobias Pankrath via Digitalmars-d-learn
I want to wrap e.g. an int and implement basic arithmetic. In the 
provided example [1] I use  two mixin templates to separately 
implement scaling (multiplication with int/double) and addition 
and subtraction with the type itself.


In the end I want to have several distinct wrappers and allow 
specific operations between them and int / double. It's important 
that the return values are typed correctly, otherwise I could use 
std.typecons.Proxy.


My problem is that both overloads of opBinary work, but not at 
the same time. As soon as I mixin both templates, they stop to 
work. If I just paste the implementation into the body of 
WrapInt, they work both at the same time though.


Could someone explain the mechanics behind it?

Thanks!

[1] https://run.dlang.io/is/WbG987




Re: Template mixin + operator overloading question

2019-10-11 Thread Boyan Lazov via Digitalmars-d-learn

On Friday, 11 October 2019 at 13:13:46 UTC, Dennis wrote:

On Friday, 11 October 2019 at 12:45:59 UTC, Boyan Lazov wrote:

Any ideas what I'm doing wrong?


Nothing, it's a bug.
https://issues.dlang.org/show_bug.cgi?id=19476


Alright, I see
Well, the alias workaround works, so that seems just as good. 
Thanks!


Re: Template mixin + operator overloading question

2019-10-11 Thread Dennis via Digitalmars-d-learn

On Friday, 11 October 2019 at 12:45:59 UTC, Boyan Lazov wrote:

Any ideas what I'm doing wrong?


Nothing, it's a bug.
https://issues.dlang.org/show_bug.cgi?id=19476



Template mixin + operator overloading question

2019-10-11 Thread Boyan Lazov via Digitalmars-d-learn

Hello,

I seem to have a problem when I use a template mixin and then try 
to overload operators both in the mixin and in a struct from 
where it's instantiated.
So the idea is that I have a few operators defined in the mixin, 
then a few more in the struct, and I want to forward all 
operations not explicitly defined in the struct to the ones in 
the mixin (and I don't want to do alias this for a variety of 
unrelated reasons).


Basically the simplest code that gives me problems is:

import std.stdio;

mixin template Impl(T) {
T v;
int opBinary(string s: "+")(T other) {
writeln("Single +");
return 0;
}
int opBinary(string s: "+")(T[] other) {
writeln("Array +");
return 0;
}
}

struct Pt {
mixin Impl!float impl;

int opBinary(string s: "*")(float other) {
writeln("Single *");
return 0;
}

int opBinary(string s, T)(T v) {
//Pt already has opBinary defined, so the operators in 
the mixin not visible
//Thought that delegating to the mixin should be done 
this way

writeln("Delegate ", s);
return impl.opBinary!(s)(v);
}
}


void main() {
Pt pt;
int r = pt + [1f, 2f];
writeln("R: ", r);
}

This results in an infinite loop though. Seems like 
Pt.opBinary!("+", float[]) is called over and over. Which is a 
bit un-intuitive to me - I'm not sure why calling 
impl.opBinary!(s) can result in endless recursion.


The problem appears only when I have 2 operators in the mixin 
that I try to forward to - e.g. the two overloads of "+" in this 
case. If I have just 1, it works ok, if I have none, the error 
message is helpful.


Any ideas what I'm doing wrong?
Thanks!


Re: How to do operator overloading for <, >, <=, >=, !=, and == between struct and int?

2019-04-21 Thread Ferhat Kurtulmuş via Digitalmars-d-learn

On Sunday, 21 April 2019 at 18:17:00 UTC, Adam D. Ruppe wrote:
On Sunday, 21 April 2019 at 18:07:08 UTC, Ferhat Kurtulmuş 
wrote:
I am writing an opencv binding and need something like: Mat m 
= another_mat > 5;


D does not support that. The comparison operators are always 
just true or false (as determined by the int opCmp or the bool 
opEquals returns), they do not return other types.


You will probably have to use a named method instead. You could 
kinda fake it with a string template arg:


Mat m = another_map.cmp!">"(5);

But I'd probably just do it

Mat m = another_map.is_greater_than(5);

which imo is more readable. but the implementations are the 
same - in both cases, your custom function.


I am a little disappointed :( I will go for named method instead. 
Thank you for a fast response.


Re: How to do operator overloading for <, >, <=, >=, !=, and == between struct and int?

2019-04-21 Thread Adam D. Ruppe via Digitalmars-d-learn

On Sunday, 21 April 2019 at 18:07:08 UTC, Ferhat Kurtulmuş wrote:
I am writing an opencv binding and need something like: Mat m = 
another_mat > 5;


D does not support that. The comparison operators are always just 
true or false (as determined by the int opCmp or the bool 
opEquals returns), they do not return other types.


You will probably have to use a named method instead. You could 
kinda fake it with a string template arg:


Mat m = another_map.cmp!">"(5);

But I'd probably just do it

Mat m = another_map.is_greater_than(5);

which imo is more readable. but the implementations are the same 
- in both cases, your custom function.


How to do operator overloading for <, >, <=, >=, !=, and == between struct and int?

2019-04-21 Thread Ferhat Kurtulmuş via Digitalmars-d-learn
I am writing an opencv binding and need something like: Mat m = 
another_mat > 5;
Docs does not cover this sitiuation: 
https://dlang.org/spec/operatoroverloading.html#compare
opBinary does not support those operators, and Section 
"Overloading <, <=, >, and >=" describes overloaded operators 
returning only int values.


My struct is defined here: 
https://github.com/aferust/opencvd/blob/master/source/opencvd/cvcore.d


Re: Operator Overloading with multiple return types

2019-03-15 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 15, 2019 at 04:29:22PM -0700, Ali Çehreli via Digitalmars-d-learn 
wrote:
> On 03/15/2019 03:48 PM, H. S. Teoh wrote:
[...]
> > Ali's example was unfortunately deceptively formatted.
> 
> My editor did that. :)

This is why I don't trust auto-formatters. ;-)


> On my work computer, I've been experimenting with pulling the 'if',
> 'in', etc to the same level as the function signature:
> 
>   int foo(T)(T t)
>   if (isBlah!T)
>   in (!t.empty) {
> // ...
>   }
[...]

Phobos style also dictates that:

int foo(T)(T t)
if (isBlah!T)
in (!t.empty)
{
...
}

In my own code, however, I find it too block-of-text-y, so I prefer to
indent it inwards:

int foo(T)(T t)
if (isBlah!T)
in (!t.empty)
{
...
}

But if your style puts { at the end of the line rather than the
beginning, this could make it even easier to confuse for a statement
inside the body.

So YMMV.


T

-- 
IBM = I'll Buy Microsoft!


Re: Operator Overloading with multiple return types

2019-03-15 Thread Ali Çehreli via Digitalmars-d-learn

On 03/15/2019 03:48 PM, H. S. Teoh wrote:

On Fri, Mar 15, 2019 at 10:30:41PM +, eXodiquas via Digitalmars-d-learn 
wrote:

On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:

[...]

Or use template constraints:

struct Vector {
   Vector opBinary(string op)(Vector rhs)
 if (op == "+") {
   return Vector();
 }

   double opBinary(string op)(Vector rhs)
 if (op == "/") {
   return 0.5;
 }
}

Ali


Thanks for the quick and simple answers, but I don't get this one. If
I do it that way the compiler doesn't know which function to call, or
am I doing something wrong?

Vector2 opBinary(string op)(Vector2 rhs) {
 if (op == "+") {
 return Vector2(this.x + rhs.x, this.y + rhs.y);
 } else if (op == "-") {
 return Vector2(this.x - rhs.x, this.y - rhs.y);
 }
 }

 float opBinary(string op)(Vector2 rhs) {
 if (op == "*") {
 return this.x * rhs.x + this.y * rhs.y;
 }
 }

This gives me the error:
overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for
opBinary

[...]

Ali's example was unfortunately deceptively formatted.


My editor did that. :)

On my work computer, I've been experimenting with pulling the 'if', 
'in', etc to the same level as the function signature:


  int foo(T)(T t)
  if (isBlah!T)
  in (!t.empty) {
// ...
  }

Ali


Re: Operator Overloading with multiple return types

2019-03-15 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 15, 2019 at 10:30:41PM +, eXodiquas via Digitalmars-d-learn 
wrote:
> On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:
[...]
> > Or use template constraints:
> > 
> > struct Vector {
> >   Vector opBinary(string op)(Vector rhs)
> > if (op == "+") {
> >   return Vector();
> > }
> > 
> >   double opBinary(string op)(Vector rhs)
> > if (op == "/") {
> >   return 0.5;
> > }
> > }
> > 
> > Ali
> 
> Thanks for the quick and simple answers, but I don't get this one. If
> I do it that way the compiler doesn't know which function to call, or
> am I doing something wrong?
> 
> Vector2 opBinary(string op)(Vector2 rhs) {
> if (op == "+") {
> return Vector2(this.x + rhs.x, this.y + rhs.y);
> } else if (op == "-") {
> return Vector2(this.x - rhs.x, this.y - rhs.y);
> }
> }
> 
> float opBinary(string op)(Vector2 rhs) {
> if (op == "*") {
> return this.x * rhs.x + this.y * rhs.y;
> }
> }
> 
> This gives me the error:
> overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for
> opBinary
[...]

Ali's example was unfortunately deceptively formatted. The `if` has to
be *outside* the function body; it's not a regular if-statement, but a
signature constraint. And there is no `else` clause to it.

Vector opBinary(string op)(Vector rhs)
if (op == '+' || op == '-')
{
/* function body begins here */
...
}

double opBinary(string op)(Vector rhs)
if (op == '*')
{
/* function body begins here */
...
}


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: Operator Overloading with multiple return types

2019-03-15 Thread H. S. Teoh via Digitalmars-d-learn
On Fri, Mar 15, 2019 at 09:35:12PM +, eXodiquas via Digitalmars-d-learn 
wrote:
[...]
> Vector opBinary(string op)(Vector rhs)
> {
> static if (op == "+") return Vector(this.x + rhs.x, this.y + rhs.y);
> else static if (op == "-") return Vector(this.x - rhs.x, this.y -
> rhs.y);
> }
> 
> As you can see for the dot product the return type has to be a
> float/double and not a vector. Is there any way to achive this
> behaivour with D2? The opMul() function is not D2 style and I don't
> want to use it.
[...]

Use signature constraints to declare different overloads depending on
what the operator is. For example:

Vector opBinary(string op)(Vector rhs)
if (op == "+" || op == "=")
{
... /* implement + and - here */
}

double opBinary(string op)(Vector rhs)
if (op == "*")
{
... /* implement dot product here */
}


T

-- 
It is widely believed that reinventing the wheel is a waste of time; but I 
disagree: without wheel reinventers, we would be still be stuck with wooden 
horse-cart wheels.


Re: Operator Overloading with multiple return types

2019-03-15 Thread drug via Digitalmars-d-learn

16.03.2019 1:30, eXodiquas пишет:

On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:

On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:

On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:

Is there any way to achive this behaivour with D2?


Yep. Just make the return type in the function declaration `auto`. 
You are then free to return a different type in each static branch.


Or use template constraints:


struct Vector {
  Vector opBinary(string op)(Vector rhs)
    if (op == "+") {
  return Vector();
    }

  double opBinary(string op)(Vector rhs)
    if (op == "/") {
  return 0.5;
    }
}

Ali


Thanks for the quick and simple answers, but I don't get this one. If I 
do it that way the compiler doesn't know which function to call, or am I 
doing something wrong?


Vector2 opBinary(string op)(Vector2 rhs) {
     if (op == "+") {
     return Vector2(this.x + rhs.x, this.y + rhs.y);
     } else if (op == "-") {
     return Vector2(this.x - rhs.x, this.y - rhs.y);
     }
     }

     float opBinary(string op)(Vector2 rhs) {
     if (op == "*") {
     return this.x * rhs.x + this.y * rhs.y;
     }
     }

This gives me the error:
overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for 
opBinary


eXodiquas

You add wrong braces (`if` here is part of method signature not its body):
```
  Vector2 opBinary(string op)(Vector2 rhs) if (op == "+")
  {
  return Vector2(this.x + rhs.x, this.y + rhs.y);
  }

  Vector2 opBinary(string op)(Vector2 rhs) if (op == "-")
  {
  return Vector2(this.x - rhs.x, this.y - rhs.y);
  }

  float opBinary(string op)(Vector2 rhs) if (op == "*")
  {
  return this.x * rhs.x + this.y * rhs.y;
  }
```


Re: Operator Overloading with multiple return types

2019-03-15 Thread eXodiquas via Digitalmars-d-learn

On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:

On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:

On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:

Is there any way to achive this behaivour with D2?


Yep. Just make the return type in the function declaration 
`auto`. You are then free to return a different type in each 
static branch.


Or use template constraints:


struct Vector {
  Vector opBinary(string op)(Vector rhs)
if (op == "+") {
  return Vector();
}

  double opBinary(string op)(Vector rhs)
if (op == "/") {
  return 0.5;
}
}

Ali


Thanks for the quick and simple answers, but I don't get this 
one. If I do it that way the compiler doesn't know which function 
to call, or am I doing something wrong?


Vector2 opBinary(string op)(Vector2 rhs) {
if (op == "+") {
return Vector2(this.x + rhs.x, this.y + rhs.y);
} else if (op == "-") {
return Vector2(this.x - rhs.x, this.y - rhs.y);
}
}

float opBinary(string op)(Vector2 rhs) {
if (op == "*") {
return this.x * rhs.x + this.y * rhs.y;
}
}

This gives me the error:
overloads (Vector2 rhs) and (Vector2 rhs) both match argument 
list for opBinary


eXodiquas


Re: Operator Overloading with multiple return types

2019-03-15 Thread Ali Çehreli via Digitalmars-d-learn

On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:

On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:

Is there any way to achive this behaivour with D2?


Yep. Just make the return type in the function declaration `auto`. You 
are then free to return a different type in each static branch.


Or use template constraints:


struct Vector {
  Vector opBinary(string op)(Vector rhs)
if (op == "+") {
  return Vector();
}

  double opBinary(string op)(Vector rhs)
if (op == "/") {
  return 0.5;
}
}

Ali


Re: Operator Overloading with multiple return types

2019-03-15 Thread Sebastiaan Koppe via Digitalmars-d-learn

On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:

Is there any way to achive this behaivour with D2?


Yep. Just make the return type in the function declaration 
`auto`. You are then free to return a different type in each 
static branch.


Operator Overloading with multiple return types

2019-03-15 Thread eXodiquas via Digitalmars-d-learn

Hi everyone,

i'm currently working on a small physics engine and I thought it 
would be a nice feature to overload the operators of my vector 
struct so I don't have to make ugly function calls just to add 
and "multiply" my vectors. The problem now is that overloading 
the addition and subtraction of my vector struct is straight 
forward because both return and take a vector, dot product is not 
working for me because it is not possible to overload a function 
by return type (at least not that I am aware of).


My code looks like the one from the dlang docs:

Vector opBinary(string op)(Vector rhs)
{
static if (op == "+") return Vector(this.x + rhs.x, this.y + 
rhs.y);
else static if (op == "-") return Vector(this.x - rhs.x, 
this.y - rhs.y);

}

As you can see for the dot product the return type has to be a 
float/double and not a vector. Is there any way to achive this 
behaivour with D2? The opMul() function is not D2 style and I 
don't want to use it.


Thank you very much,

eXodiquas


Re: Operator overloading for size_t

2019-03-15 Thread Jani Hur via Digitalmars-d-learn

On Thursday, 14 March 2019 at 19:39:53 UTC, Alec Stewart wrote:


For < and >, would one do this?


I think you'd benefit a lot by reading 
http://ddili.org/ders/d.en/operator_overloading.html (just search 
for opCmp). I bet that will eliminate most of your confusion !


Re: Operator overloading for size_t

2019-03-14 Thread Alec Stewart via Digitalmars-d-learn

On Thursday, 14 March 2019 at 18:25:17 UTC, H. S. Teoh wrote:
On Thu, Mar 14, 2019 at 06:07:46PM +, Alec Stewart via 
Digitalmars-d-learn wrote: [...]

bool opEquals(ref const Interval i) const {
// probably would be a bit more than just this, but 
for this issue

// let's just stick with this.
return d_start.opEquals(other.d_start) && 
d_end.opEquals(other.d_end);

}


There's no need to call opEquals explicitly like that. All you 
need to do is to use <, ==, and > as you normally would:


 bool opEquals(ref const Interval i) const {
 return d_start == other.d_start) && d_end == d_end;
 }


T


Thanks. I somehow managed to overthink this...

For < and >, would one do this?

size_t opCmp(ref const Interval other) const {
return d_start < other.d_start;
}

size_t opCmp(ref const Interval other) const {
return d_end < other.d_end;
}

size_t opCmp(ref const Interval other) const {
return d_start > other.d_start;
}

size_t opCmp(ref const Interval other) const {
return d_end > other.d_end;
}

Or would it better to do

size_t opCmp(ref const Interval other) const {
if (d_start < other.d_start) {
return d_start < other.d_start;
} else if (d_start > other.d_start) {
return d_start > other.d_start;
} else if (d_end < other.d_end) {
return d_end < other.d_end;
} else if (d_end > other.d_end) {
return d_end > other.d_end;
} else {
return false;
}
}




Re: Operator overloading for size_t

2019-03-14 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Mar 14, 2019 at 06:07:46PM +, Alec Stewart via Digitalmars-d-learn 
wrote:
[...]
> bool opEquals(ref const Interval i) const {
> // probably would be a bit more than just this, but for this issue
> // let's just stick with this.
> return d_start.opEquals(other.d_start) && d_end.opEquals(other.d_end);
> }

There's no need to call opEquals explicitly like that. All you need to
do is to use <, ==, and > as you normally would:

 bool opEquals(ref const Interval i) const {
 return d_start == other.d_start) && d_end == d_end;
 }


T

-- 
Без труда не выловишь и рыбку из пруда. 


Re: Operator overloading for size_t

2019-03-14 Thread Adam D. Ruppe via Digitalmars-d-learn

On Thursday, 14 March 2019 at 18:07:46 UTC, Alec Stewart wrote:

// let's just stick with this.
return d_start.opEquals(other.d_start) && 
d_end.opEquals(other.d_end);


Why not just use d_start == other.d_start && d_end == other.d_end 
there?



So should I bother with operator overloading here, or just make 
a member function?


You shouldn't often call .opEquals yourself, just write a == b 
and let the compiler translate it if it needs to.


Operator overloading for size_t

2019-03-14 Thread Alec Stewart via Digitalmars-d-learn
I thought (for shits and giggles) to try and implement the 
Aho-Corasick algorithm[1].



I thought I'd start with a struct to represent the "interval":

struct Interval {
size_t d_start;
size_t d_end;
size_t size;

this(size_t start, size_t end) {
d_start = start;
d_end = end;
size = d_end - d_start + 1;
}
}

It'd be useful to check for equality and inequality between 
instances of `Interval`, so I thought to use `.opEquals` for 
`d_start` and `d_end`.


bool opEquals(ref const Interval i) const {
// probably would be a bit more than just this, but for 
this issue

// let's just stick with this.
return d_start.opEquals(other.d_start) && 
d_end.opEquals(other.d_end);

}


But I do get an error saying

`none of the overloads  of `opEquals` are callable using argument 
types `(const(ulong), const(ulong))`, candidates are:` and it 
doesn't say the candidates.


So should I bother with operator overloading here, or just make a 
member function?


[1] https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm


Re: Templated operator overloading

2018-08-22 Thread XavierAP via Digitalmars-d-learn

On Wednesday, 22 August 2018 at 12:36:39 UTC, Simen Kjærås wrote:


Since both your opOpAssigns match equally, the compiler throws 
up. The solution is to add some sort of restriction:


This doesn't happen apparently: the operator has a left and a 
right side, even if both types define the operator, only one of 
them is on the left at each call.


It works now after Ali corrected my stupid syntax :)


Re: Templated operator overloading

2018-08-22 Thread XavierAP via Digitalmars-d-learn

On Wednesday, 22 August 2018 at 13:20:01 UTC, aliak wrote:


"void opOpAssign(string op, T)(ref Tthis, const ref T x)" looks 
like the wrong signature for opOpAssign.


Oh I'll put on my stupid hat now...

I realize I had copy-pasted the wrong syntax from the global 
function attempt, but I swear I thought I had re-typed and tested 
the right one...


It's working now :)


Re: Templated operator overloading

2018-08-22 Thread aliak via Digitalmars-d-learn

On Wednesday, 22 August 2018 at 11:58:25 UTC, XavierAP wrote:
I've been trying some things to template operator overloads. 
The reason is that I want very similar code for different 
types, but I can't use polymorphism, as they're structs rather 
than classes. Perhaps this choice is not as advantageous as I 
think, and I may change this design from structs to classes, or 
else the code duplication would be small and never subject to 
change. But now I'm just trying for the sake of learning to 
find out what works or not in terms of templated operator 
overloading, and whether the reason something doesn't work is 
by design and if mentioned in the specification, or just an 
arbitraty result of some unspecified parsing/lowering step 
order, or it depends on the compiler (I'm using dmd).


[...]


"void opOpAssign(string op, T)(ref Tthis, const ref T x)" looks 
like the wrong signature for opOpAssign. THink it needs to be:


void opOpAssign(string op, T)(const ref T x)

Then:

mixin template operator!
{
void opOpAssign(string op, T)(const ref T x)
{
writeln(this, op, x);
}
}

struct S1
{
mixin operator;
}
struct S2
{
mixin operator;
}

Cheers,
- Ali


Re: Templated operator overloading

2018-08-22 Thread Simen Kjærås via Digitalmars-d-learn

On Wednesday, 22 August 2018 at 11:58:25 UTC, XavierAP wrote:
When I want to have the same operator overloading code in both 
types however, I can't make it work:


From https://dlang.org/spec/operatoroverloading.html#binary:
"the one with the ‘better’ match is selected. It is an error for 
both to equally match."


Since both your opOpAssigns match equally, the compiler throws 
up. The solution is to add some sort of restriction:


struct S1 {
mixin opOver;
}

struct S2 {
mixin opOver;
}

mixin template opOver() {
auto opOpAssign(string op, T)(T rhs)
if (T.stringof > typeof(this).stringof) { // Here
import std.stdio;
writeln(this, op, rhs);
}
}

unittest {
S1 a;
S2 b;
a += b;
}


And a final try with a global templated function instead of a 
mixin template:


//
private void opOpAssign(string op, Tthis, T)(ref Tthis that, 
const ref T x)


This syntax would either enable the definition of operators on 
builtin types that shouldn't have them, or be perceived as 
inconsistent, so invasive operator overloading is used in D 
instead.


--
  Simen


Templated operator overloading

2018-08-22 Thread XavierAP via Digitalmars-d-learn
I've been trying some things to template operator overloads. The 
reason is that I want very similar code for different types, but 
I can't use polymorphism, as they're structs rather than classes. 
Perhaps this choice is not as advantageous as I think, and I may 
change this design from structs to classes, or else the code 
duplication would be small and never subject to change. But now 
I'm just trying for the sake of learning to find out what works 
or not in terms of templated operator overloading, and whether 
the reason something doesn't work is by design and if mentioned 
in the specification, or just an arbitraty result of some 
unspecified parsing/lowering step order, or it depends on the 
compiler (I'm using dmd).


Since there are in my case two similar types (below just a 
minimal dumb proof of concept), I want the operator(s) to work 
within the same type, or also with the other. The following code 
actually works, including type parameter inferrence, and const 
ref to avoid struct copying:


//
import std.stdio;

struct S1
{
void opOpAssign(string op, T)(const ref T x)
{
writeln(this, op, x);
}
}
struct S2
{}

void main()
{   
S1 s1;
S2 s2;
s1 *= s2;
}
//

When I want to have the same operator overloading code in both 
types however, I can't make it work:


//
private mixin template operator(Tthis)
{
void opOpAssign(string op, T)(ref Tthis, const ref T x)
{
writeln(this, op, x);
}
}

struct S1
{
mixin operator!S1;
}
struct S2
{
mixin operator!S2;
}

void main()
{   
S1 s1;
S2 s2;
s1 *= s2; // Error: s1 *= s2 is not a scalar
	s1.opOpAssign!"*"(s2); // Error: template 
test.S1.operator!(S1).opOpAssign cannot deduce function

}
//

And a final try with a global templated function instead of a 
mixin template:


//
private void opOpAssign(string op, Tthis, T)(ref Tthis that, 
const ref T x)

{
writeln(that, op, x);
}

struct S1
{}
struct S2
{}

void main()
{   
S1 s1;
S2 s2;
s1 *= s2; // Error: s1 *= s2 is not a scalar
s1.opOpAssign!"*"(s2); // OK!
}
//


Re: Using mixin templates for operator overloading.

2017-08-20 Thread Balagopal Komarath via Digitalmars-d-learn

On Sunday, 20 August 2017 at 12:46:59 UTC, Nicholas Wilson wrote:
Did you try changing the `: "+"` constraints to `if` 
constraints?


Yes. Yields the same result as this.



Re: Using mixin templates for operator overloading.

2017-08-20 Thread Nicholas Wilson via Digitalmars-d-learn
On Saturday, 19 August 2017 at 10:16:18 UTC, Balagopal Komarath 
wrote:
Let us say I want to automatically define subtraction given 
that addition and negation are defined. I tried the following 
using mixin templates. If I simply mixin the template using 
"mixin sub;", then it gives the error


[...]


Did you try changing the `: "+"` constraints to `if` constraints?


Re: Using mixin templates for operator overloading.

2017-08-20 Thread Balagopal Komarath via Digitalmars-d-learn
On Saturday, 19 August 2017 at 10:16:18 UTC, Balagopal Komarath 
wrote:
Let us say I want to automatically define subtraction given 
that addition and negation are defined. I tried the following 
using mixin templates...


I assume there is no way to do this?



Using mixin templates for operator overloading.

2017-08-19 Thread Balagopal Komarath via Digitalmars-d-learn
Let us say I want to automatically define subtraction given that 
addition and negation are defined. I tried the following using 
mixin templates. If I simply mixin the template using "mixin 
sub;", then it gives the error


tmpmixin.d(29): Error: incompatible types for ((a) - (b)): 'A!0' 
and 'A!0'


I found out that mixin using an identifier for template mixins 
and then using an alias declaration as in the code given below 
can be used to bring in overloads. But, this produces the error.


tmpmixin.d(23): Error: alias tmpmixin.A!0.A.opBinary conflicts 
with template tmpmixin.A!0.A.opBinary(string op : "+")(in A 
other) at tmpmixin.d(14)
tmpmixin.d(29): Error: template instance tmpmixin.A!0 error 
instantiating


As you can see, there is no conflict logically. One defines 
addition and the mixin defines subtraction.


What is the right way to do this?

mixin template sub()
{
alias T = typeof(this);

T opBinary(string op : "-")(in T other) const
{
return this + (-other);
}
}

struct A(int x)
{
int a;
A opBinary(string op : "+")(in A other) const
{
return A(this.a + other.a);
}
A opUnary(string op : "-")() const
{
return A(-a);
}
mixin sub ops;
alias opBinary = ops.opBinary;
}

void main()
{
import std.stdio : writeln;
auto a = A!0(5), b = A!0(6);
writeln(a-b);
}



Re: Operator Overloading + / ~

2017-06-19 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/19/17 8:16 AM, Martin Tschierschke wrote:

Just a thought it might be useful for cut-n-paste when porting code:

Would it be possible to define an operator overloading for '+'-Operator 
for strings to work as append? (like ~).
I understand, that '~' is in general a better choice than '+', so this 
is of more theoretical interest.

It is clear to me, that when I define my own string type this is possible.

Regards mt.



Just a further note, there is a reason + is not concatenation for arrays.

does "1" + "1" = "2", or "11"? In some languages, both are possible 
outcomes, and which one is used depends on subtle differences in the 
context.


With a specific operator to mean concatenation, the intent is clear. I 
would recommend you stick to using ~ for concatenation, even for your 
own types.


-Steve


Re: Operator Overloading + / ~

2017-06-19 Thread Martin Tschierschke via Digitalmars-d-learn

On Monday, 19 June 2017 at 12:22:43 UTC, ketmar wrote:

Martin Tschierschke wrote:

Just a thought it might be useful for cut-n-paste when porting 
code:


Would it be possible to define an operator overloading for 
'+'-Operator for strings to work as append? (like ~).
I understand, that '~' is in general a better choice than '+', 
so this is of more theoretical interest.
It is clear to me, that when I define my own string type this 
is possible.


Regards mt.


nope. it is not possible to overload operators for built-in 
types (and string is just an aliased array).

Thank you for lightning fast response :-)



Re: Operator Overloading + / ~

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

Martin Tschierschke wrote:


Just a thought it might be useful for cut-n-paste when porting code:

Would it be possible to define an operator overloading for '+'-Operator 
for strings to work as append? (like ~).
I understand, that '~' is in general a better choice than '+', so this is 
of more theoretical interest.

It is clear to me, that when I define my own string type this is possible.

Regards mt.


nope. it is not possible to overload operators for built-in types (and 
string is just an aliased array).


Operator Overloading + / ~

2017-06-19 Thread Martin Tschierschke via Digitalmars-d-learn
Just a thought it might be useful for cut-n-paste when porting 
code:


Would it be possible to define an operator overloading for 
'+'-Operator for strings to work as append? (like ~).
I understand, that '~' is in general a better choice than '+', so 
this is of more theoretical interest.
It is clear to me, that when I define my own string type this is 
possible.


Regards mt.



Re: Generic operator overloading for immutable types?

2017-06-14 Thread Kagamin via Digitalmars-d-learn

On Tuesday, 13 June 2017 at 19:29:26 UTC, Gary Willoughby wrote:
Is it possible for the `result` variable in the following code 
to be returned as an immutable type if it's created by adding 
two immutable types?


Why do you even want that? Such plain data structure is 
implicitly convertible to any const flavor: 
https://dpaste.dzfl.pl/c59c4c7131b2


Re: Generic operator overloading for immutable types?

2017-06-14 Thread ag0aep6g via Digitalmars-d-learn

On 06/14/2017 03:47 AM, Steven Schveighoffer wrote:
The fundamental difference is that const and immutable share a 
characteristic that mutable doesn't -- you can't mutate the data.


(... through the reference at hand.)

const and mutable share this: The data may be mutated from elsewhere.

Mutable shares as much with const as immutable does. But it's the other 
side of const, of course.


The reason const(inout) works is because const(immutable) evaluates to 
just immutable.


const() just evaluates to const. In this way, mutable is less 
"special" than immutable.


Yeah. That makes it impossible to express the proposed type. But it's 
just because of the immutable > const > mutable progression in D, which 
makes for arbitrary asymmetries between mutable and immutable.


If it were const > mutable = immutable (and if we had a `mutable` 
keyword), then `inout immutable` would work like today's `inout const`, 
`inout mutable` would be what I'm talking about, and `inout const` would 
just be the same as const.


That's not going to happen, of course. It would break everything. And 
I'm sure there are many obvious issues that I'm just ignoring here 
because the thing won't happen anyway. But it would make `inout foo` 
more symmetric.


[...]
The soundness of the function above seems good, but I don't know how to 
reason about the return type of f. Because mutable has no type modifier, 
it's hard to imagine doing this without one. And any time I think about 
how to define it, it breaks down. I can't imagine const(blah(T)) 
evaluating to mutable, no matter what blah is called, or how it works.


Literally the ONLY place this would be useful is for inout functions, 
and Andrei pretty much has declared that inout should be completely 
stricken from Phobos/druntime in favor of templates. I can't imagine any 
leeway for another type modifier.


const(inout) literally was an afterthought observation that we could 
relax the rules for this one case and get a little more usability.


Ok, I think we're in agreement. The described variant of inout would 
make sense, but isn't possible in D. It would be very awkward to 
implement the feature without changing how mutability qualifiers 
interact. And changing that would be way too disruptive. It's also not 
at all clear that it would go well with the rest of the language.


Re: Generic operator overloading for immutable types?

2017-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/17 7:51 PM, ag0aep6g wrote:

On 06/14/2017 12:45 AM, Steven Schveighoffer wrote:

No, the fact that immutable implicitly casts to const(inout) is a
special property enabled by the knowledge that immutable data can
NEVER change, so it's OK to assume it's (at least) const for all
references. The same cannot be true of const or mutable.


In other words: Immutable can't ever become mutable, at most it can
become const.

In the same vein: Mutable can't ever become immutable, at most it can
become const.

I don't see the fundamental difference. Mutable and immutable act very
much alike. They're just on opposing ends of the scale.


The fundamental difference is that const and immutable share a 
characteristic that mutable doesn't -- you can't mutate the data.


The reason const(inout) works is because const(immutable) evaluates to 
just immutable.


const() just evaluates to const. In this way, mutable is less 
"special" than immutable.



This cannot work, because g() has no idea what the true mutability of
x is. inout is not a template. This is why you can't implicitly cast
inout to anything except const, and you can't implicitly cast anything
to inout.


I don't follow. `inout const` doesn't need a template to do its thing.


Right, it's because the point at which the inout is "unwrapped" (i.e. at 
the point of return), it either becomes const or immutable. Inout 
functions can compile oblivious to how they will be called because the 
caller can completely determine the type that should be returned. It was 
the impetus to create inout in the first place -- why generate all these 
functions that do the same thing, just to change the return type, let 
the caller figure it out.



I'm not sure what you mean about implicit conversions. Obviously, an
inout result matches the corresponding inout argument(s). Doesn't matter
if that's an implicit conversion or whatever.


There is actually a difference. inout wraps one and exactly one type 
modifier. The table in that function shows what the modifier is 
depending on your collection of mutability parameters.


If ALL of them are the same, it becomes that same thing.

If any are different, you use the table to figure out. Most differences 
become const, some special cases become const(inout). This special case 
is solely to allow a function that takes both immutable and inout to 
potentially return immutable instead of just const.



Now, this code could be made to work:


bool condition;
auto f(inout int* x)
{
int* y; /* mutable now */
return condition ? x : y;
}
void main()
{
int* r1 = f(new int);
const r1 = f(new immutable int);
}


Mutable in, mutable out. Const in, const out. Immutable in, const out.
You can't get immutable out, because y is mutable, and it cannot become
immutable. Same principle as above. You never go from mutable to
immutable or the other way around, so everything's fine, no?


The soundness of the function above seems good, but I don't know how to 
reason about the return type of f. Because mutable has no type modifier, 
it's hard to imagine doing this without one. And any time I think about 
how to define it, it breaks down. I can't imagine const(blah(T)) 
evaluating to mutable, no matter what blah is called, or how it works.


Literally the ONLY place this would be useful is for inout functions, 
and Andrei pretty much has declared that inout should be completely 
stricken from Phobos/druntime in favor of templates. I can't imagine any 
leeway for another type modifier.


const(inout) literally was an afterthought observation that we could 
relax the rules for this one case and get a little more usability.


-Steve


Re: Generic operator overloading for immutable types?

2017-06-13 Thread ag0aep6g via Digitalmars-d-learn

On 06/14/2017 12:45 AM, Steven Schveighoffer wrote:
No, the fact that immutable implicitly casts to const(inout) is a 
special property enabled by the knowledge that immutable data can NEVER 
change, so it's OK to assume it's (at least) const for all references. 
The same cannot be true of const or mutable.


In other words: Immutable can't ever become mutable, at most it can 
become const.


In the same vein: Mutable can't ever become immutable, at most it can 
become const.


I don't see the fundamental difference. Mutable and immutable act very 
much alike. They're just on opposing ends of the scale.


This code doesn't work, and I see no way to make it work:


inout(int*) f(inout int* x, inout int* y)
{
return y;
}

auto g(inout int* x)
{
int* y;
return f(x, y);
}

void main()
{
int* x;
int* r1 = g(x);
}



This cannot work, because g() has no idea what the true mutability of x 
is. inout is not a template. This is why you can't implicitly cast inout 
to anything except const, and you can't implicitly cast anything to inout.


I don't follow. `inout const` doesn't need a template to do its thing. 
I'm not sure what you mean about implicit conversions. Obviously, an 
inout result matches the corresponding inout argument(s). Doesn't matter 
if that's an implicit conversion or whatever.


The goal is something that works just like `inout const`, but switching 
mutable and immutable.


I've realized that my example can be simplified:


bool condition;
auto f(inout int* x)
{
immutable int* y;
return condition ? x : y;
}
void main()
{
const r1 = f(new int);
immutable r2 = f(new immutable int);
}


That's `inout const` at work. Put a mutable or const int* in, you get a 
const int* out. Put immutable in, you get immutable out. You can't get 
mutable out, because the function might return y which is immutable, and 
it cannot become mutable.


Now, this code could be made to work:


bool condition;
auto f(inout int* x)
{
int* y; /* mutable now */
return condition ? x : y;
}
void main()
{
int* r1 = f(new int);
const r1 = f(new immutable int);
}


Mutable in, mutable out. Const in, const out. Immutable in, const out. 
You can't get immutable out, because y is mutable, and it cannot become 
immutable. Same principle as above. You never go from mutable to 
immutable or the other way around, so everything's fine, no?


Except, there's no type in D that has this meaning.


Re: Generic operator overloading for immutable types?

2017-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/17 5:58 PM, ag0aep6g wrote:

On 06/13/2017 10:50 PM, Steven Schveighoffer wrote:

const(inout) actually *is* a thing :)

It's a type constructor that can be implicitly cast from immutable.
This has advantages in some cases.

See (horribly written) table at the bottom if the inout function
section here: http://dlang.org/spec/function.html#inout-functions

Also I talked about it last year at Dconf 2016:
http://dconf.org/2016/talks/schveighoffer.html


Huh. There it is.

Took me some experimenting to understand what it does. If anyone else is
interested, this is where it clicked for me:


inout(int*) f(inout int* x, inout int* y)
{
return y;
}

inout(int*) g(inout int* x)
{
immutable int* y;
return f(x, y); /* Error: cannot implicitly convert expression f(x,
y) of type inout(const(int*)) to inout(int*) */
}


That code can't compile because g's inout return type says that it has
to return a mutable result for a mutable argument x. But y is immutable,
so that can't work.

We see in the error message that `f(x, y)` results in a `inout(const
int*)`. We can change g's return type to that (or `auto`) and the code
compiles. `inout const` enforces that the result is const or immutable.
It cannot be mutable.

This raises a question: There is no analogous inout variant that goes
the other way (to mutable and const but not immutable), is there?


No, the fact that immutable implicitly casts to const(inout) is a 
special property enabled by the knowledge that immutable data can NEVER 
change, so it's OK to assume it's (at least) const for all references. 
The same cannot be true of const or mutable.




This code doesn't work, and I see no way to make it work:


inout(int*) f(inout int* x, inout int* y)
{
return y;
}

auto g(inout int* x)
{
int* y;
return f(x, y);
}

void main()
{
int* x;
int* r1 = g(x);
}



This cannot work, because g() has no idea what the true mutability of x 
is. inout is not a template. This is why you can't implicitly cast inout 
to anything except const, and you can't implicitly cast anything to inout.


So it MUST return const(int *) (if you did auto r1 = g(x), typeof(r1) 
would be const(int *)).


-Steve


Re: Generic operator overloading for immutable types?

2017-06-13 Thread ag0aep6g via Digitalmars-d-learn

On 06/13/2017 10:50 PM, Steven Schveighoffer wrote:

const(inout) actually *is* a thing :)

It's a type constructor that can be implicitly cast from immutable. This 
has advantages in some cases.


See (horribly written) table at the bottom if the inout function section 
here: http://dlang.org/spec/function.html#inout-functions


Also I talked about it last year at Dconf 2016: 
http://dconf.org/2016/talks/schveighoffer.html


Huh. There it is.

Took me some experimenting to understand what it does. If anyone else is 
interested, this is where it clicked for me:



inout(int*) f(inout int* x, inout int* y)
{
return y;
}

inout(int*) g(inout int* x)
{
immutable int* y;
return f(x, y); /* Error: cannot implicitly convert expression f(x, 
y) of type inout(const(int*)) to inout(int*) */

}


That code can't compile because g's inout return type says that it has 
to return a mutable result for a mutable argument x. But y is immutable, 
so that can't work.


We see in the error message that `f(x, y)` results in a `inout(const 
int*)`. We can change g's return type to that (or `auto`) and the code 
compiles. `inout const` enforces that the result is const or immutable. 
It cannot be mutable.


This raises a question: There is no analogous inout variant that goes 
the other way (to mutable and const but not immutable), is there?


This code doesn't work, and I see no way to make it work:


inout(int*) f(inout int* x, inout int* y)
{
return y;
}

auto g(inout int* x)
{
int* y;
return f(x, y);
}

void main()
{
int* x;
int* r1 = g(x);
}



Re: Generic operator overloading for immutable types?

2017-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/13/17 3:58 PM, ag0aep6g wrote:

On 06/13/2017 09:29 PM, Gary Willoughby wrote:

Is it possible for the `result` variable in the following code to be
returned as an immutable type if it's created by adding two immutable
types?


Qualify the return type as `inout`:

inout(Rational) opBinary(/*...*/)(/*...*/) inout {/*...*/}

(That second `inout` is the same as the first one in your code.)

Then you get a mutable/const/immutable result when you call the method
on a mutable/const/immutable instance.

It doesn't matter a lot, though. `Rational` is a value type, so you can
convert the return value between qualifiers as you want, anyway. But it
affects what you get with `auto`, of course.


Yes exactly. I prefer personally to have value types always return 
mutable. You can always declare the result to be immutable or const, but 
declaring mutable is not as easy. e.g.:


immutable ReallyLongValueTypeName foo1();
ReallyLongValueTypeName foo2();

version(bad)
{
   auto x = foo1;
   ReallyLongValueTypeName y = foo1;
}
version(good)
{
   immutable x = foo2;
   auto y = foo2;
}



[...]

struct Rational
{
 public long numerator;
 public long denominator;

 public inout Rational opBinary(string op)(inout(Rational) other)
const


`inout` and `const` kinda clash here. Both apply to `this`. But
apparently, the compiler thinks `inout const` is a thing. No idea how it
behaves. I don't think it's a thing in the language. As far as I
understand, you should only put one of const/immutable/inout.


const(inout) actually *is* a thing :)

It's a type constructor that can be implicitly cast from immutable. This 
has advantages in some cases.


See (horribly written) table at the bottom if the inout function section 
here: http://dlang.org/spec/function.html#inout-functions


Also I talked about it last year at Dconf 2016: 
http://dconf.org/2016/talks/schveighoffer.html


However, I find it very surprising that inout and const can combine the 
way you have written it. Even though it does make logical sense. I'd 
suspect it would be a good candidate for a "you didn't really mean that" 
error from the compiler, but it might be hard to decipher from the 
parsed code.


-Steve


Re: Generic operator overloading for immutable types?

2017-06-13 Thread ag0aep6g via Digitalmars-d-learn

On 06/13/2017 09:29 PM, Gary Willoughby wrote:
Is it possible for the `result` variable in the following code to be 
returned as an immutable type if it's created by adding two immutable 
types?


Qualify the return type as `inout`:

inout(Rational) opBinary(/*...*/)(/*...*/) inout {/*...*/}

(That second `inout` is the same as the first one in your code.)

Then you get a mutable/const/immutable result when you call the method 
on a mutable/const/immutable instance.


It doesn't matter a lot, though. `Rational` is a value type, so you can 
convert the return value between qualifiers as you want, anyway. But it 
affects what you get with `auto`, of course.


[...]

struct Rational
{
 public long numerator;
 public long denominator;

 public inout Rational opBinary(string op)(inout(Rational) other) const


`inout` and `const` kinda clash here. Both apply to `this`. But 
apparently, the compiler thinks `inout const` is a thing. No idea how it 
behaves. I don't think it's a thing in the language. As far as I 
understand, you should only put one of const/immutable/inout.


Re: Generic operator overloading for immutable types?

2017-06-13 Thread Gary Willoughby via Digitalmars-d-learn
On Tuesday, 13 June 2017 at 11:36:45 UTC, Steven Schveighoffer 
wrote:


Nope, const works just fine. A clue is in your return type -- 
it's not inout!


This should work:

public Rational opBinary(string op)(Rational rhs) const

If Rational had any indirections, then inout would be required, 
and your signature wouldn't work (because you can't convert an 
inout(SomethingWithPointers) to SomethingWithPointers).


Why do I need to make the member function const, but not the 
parameter? Because the parameter is taken by value, 'this' is a 
reference.


-Steve


Is it possible for the `result` variable in the following code to 
be returned as an immutable type if it's created by adding two 
immutable types?


import std.stdio;

struct Rational
{
public long numerator;
public long denominator;

	public inout Rational opBinary(string op)(inout(Rational) other) 
const

{
static if (op == "+")
{
return inout(Rational)(0, 0);
}
else
{
static assert(0, "Operator '" ~ op ~ "' not 
implemented");
}
}
}

unittest
{
auto baz= immutable(Rational)(1, 3);
auto qux= immutable(Rational)(1, 6);
auto result = baz + qux;

writeln(typeof(result).stringof); // Result is not immutable!
}



Re: Generic operator overloading for immutable types?

2017-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/12/17 3:36 PM, H. S. Teoh via Digitalmars-d-learn 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.


Nope, const works just fine. A clue is in your return type -- it's not 
inout!


This should work:

public Rational opBinary(string op)(Rational rhs) const

If Rational had any indirections, then inout would be required, and your 
signature wouldn't work (because you can't convert an 
inout(SomethingWithPointers) to SomethingWithPointers).


Why do I need to make the member function const, but not the parameter? 
Because the parameter is taken by value, 'this' is a reference.


-Steve


Re: Generic operator overloading for immutable types?

2017-06-13 Thread Steven Schveighoffer via Digitalmars-d-learn

On 6/12/17 3:51 PM, Gary Willoughby wrote:

I don't know how H. S. Teoh managed to answer 'before' I posted but
thanks guys! :)


D programmers are *that* good.

Seriously though, for NNTP connections, timestamp is taken from the 
submitter's PC.


-Steve


Re: Generic operator overloading for immutable types?

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

On Monday, 12 June 2017 at 20:10:17 UTC, H. S. Teoh wrote:
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


Ok, thanks.


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: 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.


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: Operator overloading through UFCS doesn't work

2016-05-31 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, May 31, 2016 14:11:58 ixid via Digitalmars-d-learn wrote:
> On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
> > And the fact that allowing free functions to overload operators
> > via UFCS sends us into that territory just highlights the fact
> > that they're a horrible idea.
> >
> > - Jonathan M Davis
>
> Do you have any examples of UFCS doing bad things? Most people
> seem to very much like it yet you argue against any change that
> would benefit UFCS.
>
> You seem to prefer:
>
>  read(to(easier(much(i over i.much.easier.to.read

The primary benefit of UFCS is that you can write generic code that will
work with both member functions and free functions, allowing you to have a
free function that does something and a member function that does that same
thing more efficiently for that specific type (a prime example of this would
be a function like find where a linear search make sense in most cases but
wouldn't for certain data structures - e.g. a sorted, binary tree). So, the
"universal" aspect of UFCS is important for generic code, whereas it would
be completely unnecessary if the code weren't generic. All of the other
benefits of UFCS are highly subjective and have to do with what a particular
person thinks is easier or harder to read rather than actual, technical
benefits (though obviously writing code in a way that is easier to read for
those working on it is obviously valuable). Personally, I've dealt with
functional languages enough that I've never felt that UFCS was much of an
improvement syntactically. But we have it, and anyone is free to use it or
not as they see fit.

Regardless, what I'm arguing against here is altering operator overloading
so that it works with free functions via UFCS instead of requiring that it
be part of the type. It's a terrible idea IMHO to allow random code to add
an overloaded operator to a type rather having it actually be part of the
type's design, and in addition to that, it doesn't play at all nicely with
symbol conflicts, because you're using an operator rather than a function,
meaning that not only do you have no way to specify which version of the
overloaded operator code should use, but it would completely defeat the
purpose of using an overloaded operator in the first place even if you
could. But fortunately, Walter agrees with me (or at least did, the last
time the subject came up in the newsgroup), so I don't think that I have to
worry about overloaded operators be definable via free functions.

- Jonathan M Davis



Re: Operator overloading through UFCS doesn't work

2016-05-31 Thread ixid via Digitalmars-d-learn

On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
And the fact that allowing free functions to overload operators 
via UFCS sends us into that territory just highlights the fact 
that they're a horrible idea.


- Jonathan M Davis


Do you have any examples of UFCS doing bad things? Most people 
seem to very much like it yet you argue against any change that 
would benefit UFCS.


You seem to prefer:

read(to(easier(much(i over i.much.easier.to.read


Re: Operator overloading through UFCS doesn't work

2016-05-30 Thread pineapple via Digitalmars-d-learn
Here's one more vote for extending UFCS to operator overloading. 
Elie wrote that it's "a restriction that seems pointless and 
arbitrary"... which summarizes my own thoughts rather well, too.


There are certainly concerning scenarios that can arise from 
making this change, but the correct way to approach this problem 
is not to tell the programmer "I won't let you use that tool, 
because if you mishandle it then you might find yourself in a 
nasty mess." That's what Java does - it treats the programmer 
like an idiot - and that's why it's so universally despised.


It has consistently been my impression that this is very much not 
the sort of philosophy D follows.


Anyway, D already provides the programmer with a wealth of tools 
which, if mishandled, can place them in a nasty mess. So I think 
this is a poor rationale for withholding from the programmer one 
more.




Re: Operator overloading through UFCS doesn't work

2016-05-30 Thread Marc Schütz via Digitalmars-d-learn

On Sunday, 29 May 2016 at 07:18:10 UTC, Jonathan M Davis wrote:
On Friday, May 27, 2016 09:08:20 Marc Schütz via 
Digitalmars-d-learn wrote:
On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis 
wrote:

> The difference is that it's impossible to do
> 10.opBinary!"+"(15), so if you're forced to do
> foo.opBinary!"+"(bar) to get around a symbol conflict, it 
> won't

> work with built-in types.

Well, that begs the question: Why don't built-in types define 
`opBinary`? That's just another arbitrary irregularity, isn't 
it.


It was never intended that any op* function be called by anyone 
except where the compiler lowers code to use them. They're for 
declaring overloaded operators on user-defined types so that 
those types can be used with those operators. If you're calling 
opBinary in your own code, you're doing it wrong. And it would 
be downright silly to then add opBinary to the built-in types.


If I were to design my own language from scratch, that's actually 
how I would do it. All operators, even for built-in types, would 
just be syntax sugar for the method calls. The goal should be to 
minimize the difference between built-in and user-defined types 
as much as possible. Turtles all the way down...


They don't need operator overloading. They already have the 
operators. Operators are supposed to be used as operators, not 
functions, and if there's any need to use them as functions, 
then there's something seriously wrong. And the fact that 
allowing free functions to overload operators via UFCS sends us 
into that territory just highlights the fact that they're a 
horrible idea.


I'd say the fact that it doesn't work, and can't currently work 
for the reasons you described, points to an inconsistency in the 
language's design. It means that we have two largely overlapping 
concepts (builtin types and user defined types), where most 
language features work the same for both, but some don't.


That's not the end of the world, of course, but still...


Re: Legal operator overloading

2016-05-29 Thread Mike Parker via Digitalmars-d-learn

On Monday, 30 May 2016 at 05:54:42 UTC, Nicholas Wilson wrote:
Is it legal/possible to overload the unary * operator? Also is 
it legal/possible to individually overload the comparison 
operators and not return a bool?


Yes to unary * (see [1]). No to the rest. Comparisons are always 
lowered to opEquals or opCmp by the compiler as per [2].


[1] https://dlang.org/spec/operatoroverloading.html#unary
[2] https://dlang.org/spec/operatoroverloading.html#eqcmp


Legal operator overloading

2016-05-29 Thread Nicholas Wilson via Digitalmars-d-learn
Is it legal/possible to overload the unary * operator? Also is it 
legal/possible to individually overload the comparison operators 
and not return a bool?


(Before you ask no I'm not crazy, I am trying to make a library 
solution to multiple address spaces for supporting OpenCL/CUDA in 
D, and vector comparisons.)


Re: Operator overloading through UFCS doesn't work

2016-05-29 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, May 27, 2016 09:08:20 Marc Schütz via Digitalmars-d-learn wrote:
> On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
> > The difference is that it's impossible to do
> > 10.opBinary!"+"(15), so if you're forced to do
> > foo.opBinary!"+"(bar) to get around a symbol conflict, it won't
> > work with built-in types.
>
> Well, that begs the question: Why don't built-in types define
> `opBinary`? That's just another arbitrary irregularity, isn't it.

It was never intended that any op* function be called by anyone except where
the compiler lowers code to use them. They're for declaring overloaded
operators on user-defined types so that those types can be used with those
operators. If you're calling opBinary in your own code, you're doing it
wrong. And it would be downright silly to then add opBinary to the built-in
types. They don't need operator overloading. They already have the
operators. Operators are supposed to be used as operators, not functions,
and if there's any need to use them as functions, then there's something
seriously wrong. And the fact that allowing free functions to overload
operators via UFCS sends us into that territory just highlights the fact
that they're a horrible idea.

- Jonathan M Davis




Re: Operator overloading through UFCS doesn't work

2016-05-27 Thread Marc Schütz via Digitalmars-d-learn

On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
The difference is that it's impossible to do 
10.opBinary!"+"(15), so if you're forced to do 
foo.opBinary!"+"(bar) to get around a symbol conflict, it won't 
work with built-in types.


Well, that begs the question: Why don't built-in types define 
`opBinary`? That's just another arbitrary irregularity, isn't it.


Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Timon Gehr via Digitalmars-d-learn

On 25.05.2016 01:19, Elie Morisse wrote:

On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:

Afaik free-function operator overloads (but not in the context of
UFCS) were considered and turned down because D did not want to get
amidst discussions about adding Koenig lookup. UFCS does not do Koenig
lookup.


I don't get it, aren't the current symbol lookup rules enough to make
free function operator overloads useful? To me it looks like they are.
...


Yup. It could be argued that it is essentially a compiler bug.


Sorry for digging up this thread, just getting irritated by a
restriction that seems pointless and arbitrary.
...


It is, but it has a few vocal proponents.


Overloaded operators would suffer from the same potential abuses other
methods are subjected to if UFCS was enabled, nothing more as far as I
can see.


You are perfectly right of course. It's painful for no benefit. (For 
example, there's no way to overload e.g. '+=' for classes in a way that 
reassigns the reference.)


Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Jonathan M Davis via Digitalmars-d-learn
On Thursday, May 26, 2016 16:24:37 Elie Morisse via Digitalmars-d-learn wrote:
> On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
> > The difference is that it's impossible to do
> > 10.opBinary!"+"(15), so if you're forced to do
> > foo.opBinary!"+"(bar) to get around a symbol conflict, it won't
> > work with built-in types.
>
> Obviously operator overloading should be limited to class and
> struct types, so that's not really relevant.

It's completely relevent, because generic code is frequently going to
operate on a variety of types - including both built-in types and
user-defined types. If code is going to use +, then + must work.
opBinary!"+" is simply not going to cut it. With UFCS, if there's a
potential symbol conflict, then you can work around it - even in generic
code. But with an overloaded operator, the operator must work as an
operator, or generic code simply won't work.

> > UFCS does not have that problem, because you're dealing with
> > free functions and can choose to not use UFCS and provide the
> > full import path or to alias the function, which you can't do
> > with operators - particularly built-in operators.
>
> I still don't understand what you're getting at, unfortunately.

You don't _have_ to use UFCS. You can call the function as a normal free
function with the full import path. You can also alias the function to a
different name and use that with UFCS or import the conflicting function
with an alias so that it doesn't conflict. The overloaded operator, on the
other hand, needs to work as on overloaded operator, and we can't just call
an overloaded operator with its full import path or alias it when
importing it, because it's an overloaded operator and not just a free
function. We have ways to distinguish conflicting types with free functions,
and we don't with operators, because operators were designed to be part of
the type and not free functions. And syntactically, it really doesn't work
to provide a way to distinguish between conflicting versions of an
overloaded operator, because then you're no longer just using the operator
and might as well just be using a function.

But all I'm really doing here is saying the same thing multiple times in
slightly different ways, so if you don't get it, I don't know how to explain
it.

> Thanks for taking the time to explain, although I still fail to
> see a good justification for disabling UFCS for operators. I will
> look for more discussions on the topic and if still no opposing
> argument seems valid I might push the issue forward.

You're going to need more than a good reason why it shouldn't be allowed.
You're going to need a good reason why it should be, and I really don't
think that you're going to have one good enough to get you anywhere with
Walter. I'm fairly certain that there's a thread or two floating around
somewhere in the main newsgroup where he's responded to the issue before
though.

- Jonathan M Davis



Re: Operator overloading through UFCS doesn't work

2016-05-26 Thread Elie Morisse via Digitalmars-d-learn

On Thursday, 26 May 2016 at 06:23:17 UTC, Jonathan M Davis wrote:
The difference is that it's impossible to do 
10.opBinary!"+"(15), so if you're forced to do 
foo.opBinary!"+"(bar) to get around a symbol conflict, it won't 
work with built-in types.


Obviously operator overloading should be limited to class and 
struct types, so that's not really relevant.


UFCS does not have that problem, because you're dealing with 
free functions and can choose to not use UFCS and provide the 
full import path or to alias the function, which you can't do 
with operators - particularly built-in operators.


I still don't understand what you're getting at, unfortunately.

D was designed to be much cleaner with operator overloading 
than C++ is. It restricts what the definitions of the operators 
are so that you don't have to define as many of them to get the 
basic operations (e.g. opCmp for most of the comparison 
operators or op!"++" for both pre-increment and post-increment) 
and so that they aren't easily overloaded to do stuff that does 
not correspond to what that operator does for built-in types. D 
doesn't even use + for string concatenation, because Walter 
thought that that was operator abuse. Allowing arbitrary code 
to add overloaded operators to an existing type is not at all 
in line with that philosophy.


Regardless, there really isn't much point in arguing this. If 
you want things to change, you're going to need to convince 
Walter, which I very much doubt is going to happen.


- Jonathan M Davis


Thanks for taking the time to explain, although I still fail to 
see a good justification for disabling UFCS for operators. I will 
look for more discussions on the topic and if still no opposing 
argument seems valid I might push the issue forward.


Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, May 25, 2016 23:31:18 Elie Morisse via Digitalmars-d-learn 
wrote:
> On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
> > It's not an overloaded operator anymore at that point, and that
> > definitely fails to work for generic code, since not all
> > operators are overloaded operators. Free functions don't have
> > that problem.
>
> Sorry to reiterate the previous post but is that really the case?
>
>void FuncTemplate(...)(...) {
>  X.FreeFunc(Y);
>}
>
>import ModuleA; // contains FreeFunc
>import ModuleB; // contains a conflicting FreeFunc overload
>
>FuncTemplate!()(); // fails
>
> Where is the difference with writing generic code with operators
> (overloaded or not)?

The difference is that it's impossible to do 10.opBinary!"+"(15), so if
you're forced to do foo.opBinary!"+"(bar) to get around a symbol conflict,
it won't work with built-in types. UFCS does not have that problem, because
you're dealing with free functions and can choose to not use UFCS and
provide the full import path or to alias the function, which you can't do
with operators - particularly built-in operators.

D was designed to be much cleaner with operator overloading than C++ is. It
restricts what the definitions of the operators are so that you don't have
to define as many of them to get the basic operations (e.g. opCmp for most
of the comparison operators or op!"++" for both pre-increment and
post-increment) and so that they aren't easily overloaded to do stuff that
does not correspond to what that operator does for built-in types. D doesn't
even use + for string concatenation, because Walter thought that that was
operator abuse. Allowing arbitrary code to add overloaded operators to an
existing type is not at all in line with that philosophy.

Regardless, there really isn't much point in arguing this. If you want
things to change, you're going to need to convince Walter, which I very much
doubt is going to happen.

- Jonathan M Davis



Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Elie Morisse via Digitalmars-d-learn

On Wednesday, 25 May 2016 at 21:50:06 UTC, Jonathan M Davis wrote:
It's not an overloaded operator anymore at that point, and that 
definitely fails to work for generic code, since not all 
operators are overloaded operators. Free functions don't have 
that problem.


Sorry to reiterate the previous post but is that really the case?

  void FuncTemplate(...)(...) {
X.FreeFunc(Y);
  }

  import ModuleA; // contains FreeFunc
  import ModuleB; // contains a conflicting FreeFunc overload

  FuncTemplate!()(); // fails

Where is the difference with writing generic code with operators 
(overloaded or not)?


Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, May 25, 2016 15:46:23 Elie Morisse via Digitalmars-d-learn 
wrote:
> On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
> > On Tuesday, May 24, 2016 23:19:32 Elie Morisse via
> >
> > Digitalmars-d-learn wrote:
> >> On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> >> > Afaik free-function operator overloads (but not in the
> >> > context of UFCS) were considered and turned down because D
> >> > did not want to get amidst discussions about adding Koenig
> >> > lookup. UFCS does not do Koenig lookup.
> >>
> >> I don't get it, aren't the current symbol lookup rules enough
> >> to make free function operator overloads useful? To me it
> >> looks like they are.
> >>
> >> Sorry for digging up this thread, just getting irritated by a
> >> restriction that seems pointless and arbitrary.
> >>
> >> Overloaded operators would suffer from the same potential
> >> abuses other methods are subjected to if UFCS was enabled,
> >> nothing more as far as I can see.
> >
> > If UFCS doesn't work, because there are two free functions with
> > the same name which take the same arguments, then you can
> > differentiate between them by not using UFCS and using their
> > full import paths, or you can alias them so that they don't
> > have the same name. Neither of those would be possible with
> > operator overloading. If overloaded operators were allowed as
> > free functions, then if there were ever a symbol conflict,
> > you'd be screwed.
> >
> > - Jonathan M Davis
>
>X.FreeFunc(Y); // multiple matches error
>ModuleA.FreeFunc(X, Y); // ok
>
>X * Y; // multiple matches error
>ModuleA.opBinary!'*'(X, Y); // ok
>
> Is there much of a difference between the two?

It's not an overloaded operator anymore at that point, and that definitely
fails to work for generic code, since not all operators are overloaded
operators. Free functions don't have that problem.

- Jonathan M Davis



Re: Operator overloading through UFCS doesn't work

2016-05-25 Thread Elie Morisse via Digitalmars-d-learn

On Tuesday, 24 May 2016 at 23:43:46 UTC, Jonathan M Davis wrote:
On Tuesday, May 24, 2016 23:19:32 Elie Morisse via 
Digitalmars-d-learn wrote:

On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> Afaik free-function operator overloads (but not in the 
> context of UFCS) were considered and turned down because D 
> did not want to get amidst discussions about adding Koenig 
> lookup. UFCS does not do Koenig lookup.


I don't get it, aren't the current symbol lookup rules enough 
to make free function operator overloads useful? To me it 
looks like they are.


Sorry for digging up this thread, just getting irritated by a 
restriction that seems pointless and arbitrary.


Overloaded operators would suffer from the same potential 
abuses other methods are subjected to if UFCS was enabled, 
nothing more as far as I can see.


If UFCS doesn't work, because there are two free functions with 
the same name which take the same arguments, then you can 
differentiate between them by not using UFCS and using their 
full import paths, or you can alias them so that they don't 
have the same name. Neither of those would be possible with 
operator overloading. If overloaded operators were allowed as 
free functions, then if there were ever a symbol conflict, 
you'd be screwed.


- Jonathan M Davis


  X.FreeFunc(Y); // multiple matches error
  ModuleA.FreeFunc(X, Y); // ok

  X * Y; // multiple matches error
  ModuleA.opBinary!'*'(X, Y); // ok

Is there much of a difference between the two?


Re: Operator overloading through UFCS doesn't work

2016-05-24 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, May 24, 2016 23:19:32 Elie Morisse via Digitalmars-d-learn wrote:
> On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
> > Afaik free-function operator overloads (but not in the context
> > of UFCS) were considered and turned down because D did not want
> > to get amidst discussions about adding Koenig lookup. UFCS does
> > not do Koenig lookup.
>
> I don't get it, aren't the current symbol lookup rules enough to
> make free function operator overloads useful? To me it looks like
> they are.
>
> Sorry for digging up this thread, just getting irritated by a
> restriction that seems pointless and arbitrary.
>
> Overloaded operators would suffer from the same potential abuses
> other methods are subjected to if UFCS was enabled, nothing more
> as far as I can see.

If UFCS doesn't work, because there are two free functions with the same
name which take the same arguments, then you can differentiate between them
by not using UFCS and using their full import paths, or you can alias them
so that they don't have the same name. Neither of those would be possible
with operator overloading. If overloaded operators were allowed as free
functions, then if there were ever a symbol conflict, you'd be screwed.

- Jonathan M Davis



Re: Operator overloading through UFCS doesn't work

2016-05-24 Thread Elie Morisse via Digitalmars-d-learn

On Saturday, 13 October 2012 at 22:58:56 UTC, Timon Gehr wrote:
Afaik free-function operator overloads (but not in the context 
of UFCS) were considered and turned down because D did not want 
to get amidst discussions about adding Koenig lookup. UFCS does 
not do Koenig lookup.


I don't get it, aren't the current symbol lookup rules enough to 
make free function operator overloads useful? To me it looks like 
they are.


Sorry for digging up this thread, just getting irritated by a 
restriction that seems pointless and arbitrary.


Overloaded operators would suffer from the same potential abuses 
other methods are subjected to if UFCS was enabled, nothing more 
as far as I can see.


  1   2   3   >