Re: Struct template cannot deduce function from argument types

2018-06-27 Thread Luka Aleksic via Digitalmars-d-learn
On Wednesday, 27 June 2018 at 17:07:52 UTC, Jonathan M Davis 
wrote:
On Wednesday, June 27, 2018 16:19:56 Luka Aleksic via 
Digitalmars-d-learn wrote:

[...]



[...]


Well, for one, what's on the left side of the = doesn't 
normally affect the type of what's on the right. It does in 
some cases with literals - e.g.


[...]


Thank you very much for a clear explanation and examples of how 
to do this sort of thing idiomatically. Very useful and cleared 
up all I was confused about.


Re: Struct template cannot deduce function from argument types

2018-06-27 Thread lithium iodate via Digitalmars-d-learn

On Wednesday, 27 June 2018 at 16:19:56 UTC, Luka Aleksic wrote:

[…]
I am getting the following error:

scratch.d(14): Error: struct scratch.pair cannot deduce 
function from argument types !()(char, int), candidates are:

scratch.d(2):scratch.pair(T, U)
Failed: ["/usr/bin/dmd", "-v", "-o-", "scratch.d", "-I."]

Changing the offending line to:

pair!(char, uint) p1 = pair!(char, uint)('a', 1);

fixes the issue.

However I am interested to know why the first code couldn't 
deduce the types-- and why does it even have to try to deduce 
them, when I explicitly stated that p1 was of the type "pair of 
char and uint"?


Thanks,
L. Aleksic


Type inference does not work for struct construction. There are 
some technical problems with allowing that, such as this() having 
the capability of being a separate template itself.
Relevant issue tracker entry: 
https://issues.dlang.org/show_bug.cgi?id=6082


Your construction call does not work because the right hand side 
determines its type using only information present on the right 
hand side, in that sense you're not explicitly providing types at 
all.


In order to still be able to make concise construction calls, you 
can define a factory function:


struct Pair(A, B)
{
A a;
B b;

this(A a, B b)
{
this.a = a;
this.b = b;
}
}

Pair!(A, B) pair(A, B)(A a, B b)
{
return Pair!(A, B)(a, b);
}

void main()
{
auto p = pair(1, "test");
pragma(msg, typeof(p)); //Pair!(int, string)
}


Re: Struct template cannot deduce function from argument types

2018-06-27 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jun 27, 2018 at 04:19:56PM +, Luka Aleksic via Digitalmars-d-learn 
wrote:
[...]
> struct pair(T, U) {
>   T first;
>   U second;
> 
>   this(T arg_first, U arg_second) {
>   first = arg_first;
>   second = arg_second;
>   }
> };
> 
> void main() {
> 
>   pair!(char, uint) p1 = pair('a', 1);

The usual way I'd write this is:

auto p1 = pair!(char, uint)('a', 1);

This saves having to retype a complicated type, and also gives the
compiler the template arguments in the place where it needs them.


[...]
> I am getting the following error:
> 
> scratch.d(14): Error: struct scratch.pair cannot deduce function from
> argument types !()(char, int), candidates are:
> scratch.d(2):scratch.pair(T, U)
> Failed: ["/usr/bin/dmd", "-v", "-o-", "scratch.d", "-I."]

The reason is that the compiler runs semantic on the right-hand side of
the assignment first, before it looks at the type of p1.  The expression
`pair('a', 1)` is ambiguous, since the compiler doesn't (yet) know which
instantiation of `pair` you intended.

Writing it the way I recommend above avoids this problem.


T

-- 
Answer: Because it breaks the logical sequence of discussion.
Question: Why is top posting bad?


Re: Struct template cannot deduce function from argument types

2018-06-27 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, June 27, 2018 16:19:56 Luka Aleksic via Digitalmars-d-learn 
wrote:
> Hello,
>
> In the following code:
>

>   T first;
>   U second;
>
>   this(T arg_first, U arg_second) {
>   first = arg_first;
>   second = arg_second;
>   }
> };
>
> void main() {
>
>   pair!(char, uint) p1 = pair('a', 1);
>
> }
>
> I am getting the following error:
>
> scratch.d(14): Error: struct scratch.pair cannot deduce function
> from argument types !()(char, int), candidates are:
> scratch.d(2):scratch.pair(T, U)
> Failed: ["/usr/bin/dmd", "-v", "-o-", "scratch.d", "-I."]
>
> Changing the offending line to:
>
> pair!(char, uint) p1 = pair!(char, uint)('a', 1);
>
> fixes the issue.
>
> However I am interested to know why the first code couldn't
> deduce the types-- and why does it even have to try to deduce
> them, when I explicitly stated that p1 was of the type "pair of
> char and uint"?
>
> Thanks,
> L. Aleksic

Well, for one, what's on the left side of the = doesn't normally affect the
type of what's on the right. It does in some cases with literals - e.g.

char c = 'a';

compiles just fine in spite of the fact that 'a' is a dchar, but if what's
on the right-hand side is not a literal, then the type has to match or be
implicitly convertible to the type of the variable it's initializing or
being assigned to. And it's definitely not the case that any template
instantitaions on the right-hand side get instantiated based on what's on
the left. pair('a', 1) has to compile on its own and result in a type which
implicitly converts to pair!(char, uint) for your code to work, and that's
definitely not the case.

The other big issue here is that the only time that templates are ever
implicitly instantiated is for functions - which is why it's called IFTI
(implicit function template instantiation). Even something like

struct S(T = int)
{
}

S s;

would not compile, because S is a template. The code would have to use

S!() s;

or

S!int s;

S by itself is not a type. It's a template. This can be annoying at times,
but it stems from the fact that you'd get various ambiguities otherwise.
e.g. if S was implicitly instantiatied as S!int, then what would

alias Foo = S;

mean? It could be the template, or it could be the instantiation of the
template. Because of that, implicit instantation never happens for types.

So, when the compiler sees pair('a', 1), there is no function named pair.
There is no constructor. There isn't even a type named pair.
pair!(char, uint) would be a type, or it would be a constructor, but pair is
just a template. So, when it sees

pair!(char, uint) p1 = pair('a', 1);

it sees you trying to call a function that doesn't exist. There is no
function pair - not even a templated function named pair.

However, while there is ambiguity in implicitly instantiating templated
types, for functions, there is no ambiguity (since the function call syntax
is unambiguous). So, templated functions _can_ have their template arguments
infered (hence IFTI). So, the typical solution to this sort of problem is to
create a helper function. e.g.

struct Pair(T, U)
{
  T first;
  U second;

  this(T arg_first, U arg_second)
  {
  first = arg_first;
  second = arg_second;
  }
}

auto pair(T, U)(T first, U second)
{
return Pair!(T, U)(first, second);
}

That way, you have a function which can take advantage of IFTI to infer the
template arguments (what you'd do for naming in your case if you want to use
camelCasing for types, I don't know, but normally, D code uses PascalCasing
for types and camelCasing for functions, which makes the naming pretty
straightforward in cases like this). Now, even then

Pair!(char, uint) p1 = pair('a', 1);

won't compile, because the literal 'a' defaults to dchar, and the literal 1,
defaults to int. So, pair('a', 1) would have the type Pair!(dchar, int). 1u
could be used to turn 1 into a uint literal, but you'd have to use a cast to
force 'a' to be a char. e.g.

Pair!(char, uint) p1 = pair(cast(char)'a', 1u);

Now, normally, you also wouldn't put the type on the left-hand side of a
variable declaration like that. You'd just use auto - e.g.

auto p1 = pair('a', 1);

but if you want that specific type, you'd need to do something like

auto p1 = pair(cast(char)'a', 1u);

or

auto p1 = pair!(char, uint)('a', 1);

though if you're doing that, you don't even need the helper function and
could just do

auto p1 = Pair!(char, uint)('a', 1);

The helper function does often help though, much as it's less helpful with
those particular literals given the type that you want.

In any case, I would point out that unless you're doing something beyond
what's typically for a pair or tuple type, there's no reason to declare a
Pair type like what you have here. std.typecons.Tuple already takes care of
that for you. So, Tuple!(char, uint) would declare basically the same type
that you were trying to use and tuple can be used to construct on - e.g.

auto p1 = tuple('a', 1);

or

auto p1 = tuple(

Struct template cannot deduce function from argument types

2018-06-27 Thread Luka Aleksic via Digitalmars-d-learn

Hello,

In the following code:

struct pair(T, U) {
T first;
U second;

this(T arg_first, U arg_second) {
first = arg_first;
second = arg_second;
}
};

void main() {

pair!(char, uint) p1 = pair('a', 1);

}

I am getting the following error:

scratch.d(14): Error: struct scratch.pair cannot deduce function 
from argument types !()(char, int), candidates are:

scratch.d(2):scratch.pair(T, U)
Failed: ["/usr/bin/dmd", "-v", "-o-", "scratch.d", "-I."]

Changing the offending line to:

pair!(char, uint) p1 = pair!(char, uint)('a', 1);

fixes the issue.

However I am interested to know why the first code couldn't 
deduce the types-- and why does it even have to try to deduce 
them, when I explicitly stated that p1 was of the type "pair of 
char and uint"?


Thanks,
L. Aleksic