Thread overview
why compiler try use my sqrt not std.math?
May 08, 2019
KnightMare
May 08, 2019
KnightMare
May 08, 2019
Cym13
May 08, 2019
Cym13
May 08, 2019
Jonathan M Davis
May 08, 2019
KnightMare
May 08, 2019
Simen Kjærås
May 08, 2019
KnightMare
May 08, 2019
Cym13
May 08, 2019
KnightMare
May 08, 2019
// ============= test5.d ==============
import std.stdio, std.conv, std.bigint, std.math, std.algorithm;

ulong sqrt( ulong n ) { return cast( ulong )real( n ).sqrt; }
ulong sqrt1( ulong n ) { return cast( ulong )real( n ).sqrt.ceil; }

void main() { }
// ============= EOF test5.d ==============

and result is:
test5.d(5): Error: std.math.ceil called with argument types (ulong) matches both:
C:\programz\D\ldc2\bin\..\import\std\math.d(4869):     std.math.ceil(real x)
and:
C:\programz\D\ldc2\bin\..\import\std\math.d(4982):     std.math.ceil(float x)

prog compiles ok when I comment my ulong sqrt( ulong )

IMO about sqrt1 (I tried cast(real)n instead real(n) too with same result)
real(n).sqrt should to use real std.math.sqrt(real) that returns real. so ceil should be used real std.math.ceil(real). and after that only cast to ulong.

what happened here?
May 08, 2019
so compiler thinks and try convert my code upper to
ulong sqrt1( ulong n ) {
  return cast( ulong )ceil<float OR real?>( @ret(ulong)my_sqrt( cast( ulong )real( n )));
}
why that? I didnt ask that.

yes, I know that I can add inside sqrt1
import std.math : sqrt;
but.. WHY?
May 08, 2019
compiler should select right sqrt by arg types. it shouldnt prefer my sqrt( ulong ) over std.math.sqrt( real ) when I pass to sqrt real with explicit cast

it has from std.math
float sqrt( float )
double sqrt( double )
real sqrt( real )
I added
ulong sqrt( ulong )
and try invoke sqrt( real(SomeVal))
we have real arg, so call std.math.sqrt( real ). no doubt!
WHY compiler tries be too much smart and looks stupid and buggy?

in case no misunderstanding what ceil should be called I missed this BUG (compiler call MY sqrt(ulong)) before some tests or debugging session

May 08, 2019
On Wednesday, 8 May 2019 at 08:28:57 UTC, KnightMare wrote:
> so compiler thinks and try convert my code upper to
> ulong sqrt1( ulong n ) {
>   return cast( ulong )ceil<float OR real?>( @ret(ulong)my_sqrt( cast( ulong )real( n )));
> }
> why that? I didnt ask that.
>
> yes, I know that I can add inside sqrt1
> import std.math : sqrt;
> but.. WHY?

First of all, such questions are better suited for the Learn section if you want quality answers.

When you define a function it's reasonnable to assume that you want to use it, that's probably why D (and any language I know really) resolves function names from the most local scope to the largest one.

If it worked the other way arround you could define a function like byLine thinking that this name is safe and be equally confused when the program tries making web requests because you have no clue that it's actually already defined in std.net.curl. Here at least you're confused but you have the function before you so that confusion shouldn't last as long.

It's also true inside that function's definition: recursive functions are common and they need that mechanics to work.

Now, in my opinion, the right way to fix your code (short of choosing another name) is to specify the function you wish to use explicitely:

    import std.math;

    ulong sqrt(ulong n) {
        return cast(ulong) std.math.sqrt(real(n));
    }

And for reference, should you want to name the current module's implementation of sqrt, you would do as such:

    ulong sqrt(ulong n) {
        return cast(ulong) .sqrt(real(n));
    }

But of course here it would cause infinite recursion and stack overflow.
May 08, 2019
On Wednesday, 8 May 2019 at 08:48:40 UTC, Cym13 wrote:
> On Wednesday, 8 May 2019 at 08:28:57 UTC, KnightMare wrote:
>> [...]
>
> First of all, such questions are better suited for the Learn section if you want quality answers.
>
> [...]

I hadn't noticed the type issue, my answer is off.
May 08, 2019
On Wednesday, 8 May 2019 at 08:16:27 UTC, KnightMare wrote:
> // ============= test5.d ==============
> import std.stdio, std.conv, std.bigint, std.math, std.algorithm;
>
> ulong sqrt( ulong n ) { return cast( ulong )real( n ).sqrt; }
> ulong sqrt1( ulong n ) { return cast( ulong )real( n ).sqrt.ceil; }
>
> void main() { }
> // ============= EOF test5.d ==============
>
> and result is:
> test5.d(5): Error: std.math.ceil called with argument types (ulong) matches both:
> C:\programz\D\ldc2\bin\..\import\std\math.d(4869):     std.math.ceil(real x)
> and:
> C:\programz\D\ldc2\bin\..\import\std\math.d(4982):     std.math.ceil(float x)
>
> prog compiles ok when I comment my ulong sqrt( ulong )
>
> IMO about sqrt1 (I tried cast(real)n instead real(n) too with same result)
> real(n).sqrt should to use real std.math.sqrt(real) that returns real. so ceil should be used real std.math.ceil(real). and after that only cast to ulong.
>
> what happened here?

When a function overload is looked up, the most local symbol is used. In this case, that's your sqrt function.

We can even prove this by testing sqrt:

import std.math;
ulong sqrt( ulong n ) { return cast( ulong )real( n ).sqrt; }

void main() {
    assert(4UL.sqrt == 2);
}

The above program will hang, since sqrt calls itself recursively.

When you comment out sqrt, the imported sqrt will be used instead.

To combine the overload sets, you will need to explicitly mention std.math.sqrt somehow, either:

    import std.math : sqrt;

or

    import std.math;
    alias sqrt = std.math.sqrt;

Once that's done, your code will do the Right Thing™.

--
  Simen
May 08, 2019
OFFTOPIC
Dlang is good language but sometimes happens big badaboom (shit in other words):
you just sit and write code. almost same code as c++ or c#.
and happens something bad/unexpected in lines where you not see any criminal (no typos, no semantic issues). u just write working code in your mind-stream, u write such code many times in other languages and it worked as expected.
and... BOOOM!.. you are thrown out of the stream.. what happened here?

u asked questions on forum and u will get an answer in few hours but till u sit and reflection yourself and question of universe:
why author do this way? he had some reason for this.
why other langs do way as I expected? maybe appear some cases where this way better than in other langs? OR maybe such things works same in other langs and I just forgot it? FK! maybe I have alzheimer's disease? I am too young for this shit!..

after 2 such bigbadaboom people lefts Dlang. I can understand that.
it like Russian language - u have 1/4 of book rules and 3/4 exceptions from this rules, u shouldnt understand it, u must remember it and that all, dont think, dont doubt!

well, lets write all unclear cases of Dlang in some page (better home page)
1) case with sqrt: I compiler prefer func in this file/module over func in included module and it ignores types of parameters?
2) why
(string s) { return cast( int )s.length; } typeof is int delegate( string )
but
(string s) => { return cast( int )s.length; } typeof is int delegate() delegate( string )
3) add more, dont be shy
May 08, 2019
On Wednesday, 8 May 2019 at 09:20:35 UTC, KnightMare wrote:
> 2) why
> (string s) { return cast( int )s.length; } typeof is int delegate( string )
> but
> (string s) => { return cast( int )s.length; } typeof is int delegate() delegate( string )


That I can answer:

  (string s) => { return cast( int )s.length; }

is equivalent to

  (string s) => (){ return cast( int )s.length; }

since empty parens can be ommited.

So it's a delegate that returns a delegate. Don't put {} there.

The equivalent with => will be:

  (string s) => cast( int )s.length
May 08, 2019
tale in Russian
https://bormor.livejournal.com/354899.html

translation over google translator:
One rather big village had a rather large flock of sheep. And, as usual, the shepherd was put in charge of the flock - and the most vocal of the village boys was chosen for the role of the shepherd, so that it could be heard from afar. And so, he grazes the first day of these sheep, and suddenly a wolf! Well, the shepherd immediately screamed, the village ran up, scared the wolf, praised the shepherd, and went back. An hour passes - the wolf has come again! The shepherd screams, the village people come running, the wolf runs away, everyone’s leaving. Another hour passed — the shepherd screamed again, the village men run again — yes, surely, no deception, the wolf is in place, chasing him away and going about his business. Another hour - screams again; Well, the villagers could not stand it, they ran, the shepherd was mortified and removed from harm's way into the army - let him yell as much as he could. And they put a deaf-and-dumb fool to the sheep, and they even blindfolded him with a handkerchief so that he wouldn’t see it by chance.
And since then, in the village, peace and quiet. Sheep, of course, disappear, but on the other hand, there was much less cause for concern.

so "peace and quiet" should be preference by proging lang writers.
or.. am I "most vocal of the village boys"? :)
May 08, 2019
On Wednesday, May 8, 2019 2:52:34 AM MDT Cym13 via Digitalmars-d wrote:
> On Wednesday, 8 May 2019 at 08:48:40 UTC, Cym13 wrote:
> > On Wednesday, 8 May 2019 at 08:28:57 UTC, KnightMare wrote:
> >> [...]
> >
> > First of all, such questions are better suited for the Learn section if you want quality answers.
> >
> > [...]
>
> I hadn't noticed the type issue, my answer is off.

It doesn't matter, because the local scope always wins when there's a symbol conflict with an imported symbol. If you try to use the same name as a symbol you're importing, and you want to use the imported symbol, then you need to either use the full import path when using the symbol, rename it when importing it, or alias the symbol (using the full path name) to a different name. In the latter two cases, you then of course have to use the new name for the symbol and not the original name. IIRC, you have the same problem when you have a local import which imports symbols explicitly instead of the entire module, because that effectively aliases the symbol with that name in the local scope.

You basically can't overload symbols from other modules in the local scope, because the language assumes that you want the local symbol. In general though, D doesn't go with the "best match" with overload sets. It will take the exact match, and it will do implicit conversions if there's only one possible choice, but once multiple overloads would all accept the same type but none of them accept the exact type of the argument, then it's an error. D is much pickier about overloads than C++ in order to avoid issues with function hijacking. It can get annoying sometimes, but by being pickier about it, it avoids a whole class of bugs that exist in C++.

https://dlang.org/articles/hijack.html

- Jonathan M Davis