Thread overview
How to create a custom max() function without the ambiguity error.
Dec 06, 2019
realhet
Dec 06, 2019
Ferhat Kurtulmuş
Dec 06, 2019
realhet
Dec 06, 2019
Ferhat Kurtulmuş
Dec 06, 2019
realhet
Dec 06, 2019
Mike Parker
Dec 06, 2019
Andrea Fontana
December 06, 2019
Hi,

I'm trying to use a popular function name "max", and extend it for my special types:

For example:

module utils;
MyType max(in MyType a, in MyType a){...}  //static function

struct V3f{
  V3f max(in V2f b){...} //member function
}

module gl3n;
vec3 max(in vec3 a, in vec3 a) //another static function in different module

I also want to use std.algorithm.comparison.max as well.


I know that the ambiguity error can be avoided by public importing all the various max implementations into one place, but how to do this when I want to use 3 modules? Need a 4th module to combine them all? Is there a nicer way?
Another question that is it possible to extend the the template function "to" in more than one module and use it easily from my main project modules?

December 06, 2019
On Friday, 6 December 2019 at 12:34:17 UTC, realhet wrote:
> Hi,
>
> I'm trying to use a popular function name "max", and extend it for my special types:
>
> For example:
>
> module utils;
> MyType max(in MyType a, in MyType a){...}  //static function
>
> struct V3f{
>   V3f max(in V2f b){...} //member function
> }
>
> module gl3n;
> vec3 max(in vec3 a, in vec3 a) //another static function in different module
>
> I also want to use std.algorithm.comparison.max as well.
>
>
> I know that the ambiguity error can be avoided by public importing all the various max implementations into one place, but how to do this when I want to use 3 modules? Need a 4th module to combine them all? Is there a nicer way?
> Another question that is it possible to extend the the template function "to" in more than one module and use it easily from my main project modules?

how about this:

import std.stdio;
import std.algorithm.comparison: max1 = max;

int max(int a, int b){ // dummy max
    return 5;
}


void main(){
    int a = 2;
    int b = 3;

    max1(a, b).writeln; // writes 3

}
December 06, 2019
On Friday, 6 December 2019 at 13:04:57 UTC, Ferhat Kurtulmuş wrote:
> On Friday, 6 December 2019 at 12:34:17 UTC, realhet wrote:
>> Hi,
>>
>> I'm trying to use a popular function name "max", and extend it for my special types:
>>
>> For example:
>>
>> module utils;
>> MyType max(in MyType a, in MyType a){...}  //static function
>>
>> struct V3f{
>>   V3f max(in V2f b){...} //member function
>> }
>>
>> module gl3n;
>> vec3 max(in vec3 a, in vec3 a) //another static function in different module
>>
>> I also want to use std.algorithm.comparison.max as well.
>>
>>
>> I know that the ambiguity error can be avoided by public importing all the various max implementations into one place, but how to do this when I want to use 3 modules? Need a 4th module to combine them all? Is there a nicer way?
>> Another question that is it possible to extend the the template function "to" in more than one module and use it easily from my main project modules?
>
> how about this:
>
> import std.stdio;
> import std.algorithm.comparison: max1 = max;
>
> int max(int a, int b){ // dummy max
>     return 5;
> }
>
>
> void main(){
>     int a = 2;
>     int b = 3;
>
>     max1(a, b).writeln; // writes 3
>
> }

Thx for answering!

This is what I want to avoid: To use extra identifiers or imports for the same semantic task.

------------------------
module m1;
public import std.algorithm.comparison: max;
struct MyType{ int x;}
MyType max(in MyType a, in MyType a){ return a.x>b.x ? a : b; }


module main;
import m1;

------------------------
From here: the max() is working for MyType and also for the types supported by std.algo.comparison.max.

BUT! What if I want to import another module which is overloading max?! It will be an ambiguity between m1 and the other module.
I'm searching for a clever solution, not just manually reimporting everything in every module where I use multiple modules which also manually reimporting those simple names like 'max'.

December 06, 2019
On Friday, 6 December 2019 at 12:34:17 UTC, realhet wrote:
> Hi,
>
> I'm trying to use a popular function name "max", and extend it for my special types:
>
> For example:
>
> module utils;
> MyType max(in MyType a, in MyType a){...}  //static function
>
> struct V3f{
>   V3f max(in V2f b){...} //member function
> }
>
> module gl3n;
> vec3 max(in vec3 a, in vec3 a) //another static function in different module
>
> I also want to use std.algorithm.comparison.max as well.
>
>
> I know that the ambiguity error can be avoided by public importing all the various max implementations into one place, but how to do this when I want to use 3 modules? Need a 4th module to combine them all? Is there a nicer way?
> Another question that is it possible to extend the the template function "to" in more than one module and use it easily from my main project modules?

What about:

int max(int a, int b){ return 0; }

void main()
{
    .max(3,4).writeln;  // 0
    std.algorithm.comparison.max(3,4).writeln; // 4
}
December 06, 2019
On Friday, 6 December 2019 at 13:25:24 UTC, realhet wrote:
> On Friday, 6 December 2019 at 13:04:57 UTC, Ferhat Kurtulmuş wrote:
>> [...]
>
> Thx for answering!
>
> [...]

In d you can also use scoped imports: https://dlang.org/spec/module.html#scoped_imports

December 06, 2019
On Friday, 6 December 2019 at 14:55:18 UTC, Ferhat Kurtulmuş wrote:
> On Friday, 6 December 2019 at 13:25:24 UTC, realhet wrote:
>> On Friday, 6 December 2019 at 13:04:57 UTC, Ferhat Kurtulmuş wrote:
>>> [...]
>>
>> Thx for answering!
>>
>> [...]
>
> In d you can also use scoped imports: https://dlang.org/spec/module.html#scoped_imports

Yea, I know about that.
I also read the documentation about module imports, but in reality it feels like a bit different.

Here's my latest attempt on EXTENDING std.algorithm.max's functionality with a max operation on a custom type.
The type is the GLSL vec2 type which does the max operation component-wise.
The D std implementation uses the < operator, but with overriding that for my custom type it is impossible to realise. -> max(vec2(1, 2), vec2(2,1)) == vec2(2,2)

//So here is my helper module:
-----------------------------------------------------
module testimport_a;

import std.algorithm;

struct vec2{ float x, y; }

auto max(in vec2 a, in vec2 b){
  return vec2(max(a.x, b.x),
              max(a.y, b.y));
}

import std.algorithm: max;

// and the main module ////////////////////////////////

module testimport_main;

import std.stdio, testimport_a;

void main(){
  auto a = vec2(1, 2),
       b = vec2(0, 5);

  max(a, b).writeln;
  max(1, 2).writeln;
}

------------------------------------------------------

Both of the max instructions are working nicely.
But here are all the things/restrictions which aren't as nice:

- in the imported module it is really important, to put my max() function BEFORE the std one. The std implementation tries to serve EVERYTHING, but it fails the compilation when it check the < operator (which is non-existent on 2d vectors).

- It doesn't matter if I use public import or not. When it finds any compatible max() inside the helper unit's functions, and its imported functionst that are specified by name, it will compile it.

- It is really important to import the original max() by name. (After my narrower max())

- If I import std.algorithm in the main module, no matter the order, it will fail. As the std.algorithm.max alone is unable to serve vec2 types.

- I tried to make one more module, to be able to use max on vec2, vec3 and everything else, but I failed. none of the my random guessing worked.
December 06, 2019
On Friday, 6 December 2019 at 21:02:53 UTC, realhet wrote:

>
> Here's my latest attempt on EXTENDING std.algorithm.max's functionality with a max operation on a custom type.
> The type is the GLSL vec2 type which does the max operation component-wise.
> The D std implementation uses the < operator, but with overriding that for my custom type it is impossible to realise. -> max(vec2(1, 2), vec2(2,1)) == vec2(2,2)

The reason you're having so much trouble with this is that you're violating the contract of max. It's a template, so it's already set up to work with custom types without any need to write a custom max function, as long as the types adhere to the contract.

Consider other functions in std.algorithm, such as sort or equal, that allow you to pass a custom predicate. max doesn't have that because, by defintion, there is only one comparison for it to do: >. Any type that doesn't support that isn't going to work with max.

Moreover, your return value violates the function's contract:

"Iterates the passed arguments and return the maximum value."

You aren't returning the maximum value. You're returning a new value constructed from the maximum components of the two parameters. That is not the same behavior as max(1, 3).

Given that your function has a different contract, it should also have a different name.