www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 9286] New: std.conv fails to compile with Nullable

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286

           Summary: std.conv fails to compile with Nullable
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: regression
          Priority: P2
         Component: Phobos
        AssignedTo: nobody puremagic.com
        ReportedBy: jens.k.mueller gmx.de


--- Comment #0 from jens.k.mueller gmx.de 2013-01-09 02:47:57 PST ---
dmd 2.061 introduced the following regression.
The code

unittest                                                                        
{                                                                               
    import std.typecons;                                                        
    import std.conv;                                                            
    auto f = to!(Nullable!(uint))("12");                                        
    assert(f == 12);                                                            
}

used to compile and work with dmd 2.060. Now it fails with

/usr/local/bin/../src/phobos/std/conv.d(274): Error: template std.conv.toImpl
does not match any function template declaration. Candidates are:
/usr/local/bin/../src/phobos/std/conv.d(330):        std.conv.toImpl(T, S)(S
value) if (isImplicitlyConvertible!(S, T) && !isEnumStrToStr!(S, T) &&
!isNullToStr!(S, T))
/usr/local/bin/../src/phobos/std/conv.d(436):        std.conv.toImpl(T, S)(ref
S s) if (isRawStaticArray!(S))
/usr/local/bin/../src/phobos/std/conv.d(450):        std.conv.toImpl(T, S)(S
value) if (is(S : Object) && !is(T : Object) && !isSomeString!(T) &&
hasMember!(S, "to") && is(typeof(S.init.to!(T)()) : T))
/usr/local/bin/../src/phobos/std/conv.d(471):        std.conv.toImpl(T, S)(S
value) if (is(typeof(S.init.opCast!(T)()) : T) && !isExactSomeString!(T))
/usr/local/bin/../src/phobos/std/conv.d(502):        std.conv.toImpl(T, S)(S
value) if (!isImplicitlyConvertible!(S, T) && is(T == struct) &&
is(typeof(T(value))))
/usr/local/bin/../src/phobos/std/conv.d(274):        ... (16 more, -v to show)
...
/usr/local/bin/../src/phobos/std/conv.d(330): Error: template std.conv.toImpl
cannot deduce template function from argument types !(Nullable!(uint))(string)
/usr/local/bin/../src/phobos/std/conv.d(274): Error: template instance
toImpl!(Nullable!(uint)) errors instantiating template
test.d(9): Error: template instance std.conv.to!(Nullable!(uint)).to!(string)
error instantiating

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 09 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286


jens.k.mueller gmx.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|std.conv fails to compile   |std.conv.parse fails to
                   |with Nullable               |compile with Nullable


--- Comment #1 from jens.k.mueller gmx.de 2013-01-09 02:51:25 PST ---
Actually std.conv.parse is called by std.conv.to. Thus, the better example is:

unittest                                                                        
{                                                                               
    import std.typecons;                                                        
    import std.conv;                                                            
    auto f = parse!(Nullable!(uint))("12");                                     
    assert(f == 12);                                                            
}

which fails with

test.d(9): Error: template std.conv.parse does not match any function template
declaration. Candidates are:
/usr/local/bin/../src/phobos/std/conv.d(1724):        std.conv.parse(Target,
Source)(ref Source s) if (isSomeChar!(ElementType!(Source)) &&
isIntegral!(Target) && !is(Target == enum))
/usr/local/bin/../src/phobos/std/conv.d(1978):        std.conv.parse(Target,
Source)(ref Source s, uint radix) if (isSomeChar!(ElementType!(Source)) &&
isIntegral!(Target) && !is(Target == enum))
/usr/local/bin/../src/phobos/std/conv.d(2075):        std.conv.parse(Target,
Source)(ref Source s) if (isExactSomeString!(Source) && is(Target == enum))
/usr/local/bin/../src/phobos/std/conv.d(2134):        std.conv.parse(Target,
Source)(ref Source p) if (isInputRange!(Source) &&
isSomeChar!(ElementType!(Source)) && !is(Source == enum) &&
isFloatingPoint!(Target) && !is(Target == enum))
/usr/local/bin/../src/phobos/std/conv.d(2620):        std.conv.parse(Target,
Source)(ref Source s) if (isExactSomeString!(Source) &&
staticIndexOf!(Unqual!(Target), dchar, Unqual!(ElementEncodingType!(Source)))
= 0)

/usr/local/bin/../src/phobos/std/conv.d(1724): Error: template std.conv.parse cannot deduce template function from argument types !(Nullable!(uint))(string) test.d(9): Error: template instance parse!(Nullable!(uint)) errors instantiating template -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #2 from jens.k.mueller gmx.de 2013-01-09 02:56:06 PST ---
Tracking it further down:
isIntegral!(Nullable!(uint)) used to be true now it is false.

Is this expected to be true or false?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286


bearophile_hugs eml.cc changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |bearophile_hugs eml.cc


--- Comment #3 from bearophile_hugs eml.cc 2013-01-09 03:13:32 PST ---
(In reply to comment #2)
 Tracking it further down:
 isIntegral!(Nullable!(uint)) used to be true now it is false.
 
 Is this expected to be true or false?

From a recent discussion I think this is now desired. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #4 from jens.k.mueller gmx.de 2013-01-09 03:18:37 PST ---
(In reply to comment #3)
 (In reply to comment #2)
 Tracking it further down:
 isIntegral!(Nullable!(uint)) used to be true now it is false.
 
 Is this expected to be true or false?

From a recent discussion I think this is now desired.

Can you point me to this discussion? Because I'm unsure whether this is a good move. What if write my own integral type? That type won't be usable with code using isIntegral. If you want to make sure that you have a built-in integral you should to something like isBuiltIn!T && isIntegral!T. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286


Jonathan M Davis <jmdavisProg gmx.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jmdavisProg gmx.com


--- Comment #5 from Jonathan M Davis <jmdavisProg gmx.com> 2013-01-09 03:32:01
PST ---
std.traits is purposefully _not_ taking implict conversion into account (doing
otherwise would cause havoc with template constraints), and isIntegral
specifically says "Detect whether $(D T) is a built-in integral type." And it's
not like isIntegral could be made to work for user-defined types, as integral
types don't have an API specific to themselves. The trait has to know all of
the types that count as being integral types.

To do the conversion that you're looking for, just convert to uint first:

    auto f = to!(Nullable!uint)(to!uint("12"));

or

    auto f = Nullable!uint(to!uint("12"));

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #6 from jens.k.mueller gmx.de 2013-01-09 03:43:24 PST ---
(In reply to comment #5)
 std.traits is purposefully _not_ taking implict conversion into account (doing
 otherwise would cause havoc with template constraints), and isIntegral
 specifically says "Detect whether $(D T) is a built-in integral type." And it's
 not like isIntegral could be made to work for user-defined types, as integral
 types don't have an API specific to themselves. The trait has to know all of
 the types that count as being integral types.

I perfectly agree that isIntegral now conforms to the documentation. Just the name is misleading. Why is it impossible to make isIntegral work for user-defined types in the same way as e.g. isInputRange works? They do have an API. Just to mention some you use +, -, *, / etc. You just need to fix this set.
 To do the conversion that you're looking for, just convert to uint first:
 
     auto f = to!(Nullable!uint)(to!uint("12"));
 
 or
 
     auto f = Nullable!uint(to!uint("12"));

Can't do this as this happens inside getopt. I pass getopt a Nullable and later check whether it was actually set by getopt. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #7 from Jonathan M Davis <jmdavisProg gmx.com> 2013-01-09 03:51:47
PST ---
 Why is it impossible to make isIntegral work for user-defined types in the 
 same way as e.g. isInputRange works?
 They do have an API. Just to mention some you use +, -, *, / etc. You just 
 need to fix this set.

Because those operations aren't unique to integral types. They're not even necessarily unique to _numeric_ types. Input ranges have fairly a unique API, so you can test for it, but integral types don't have an API that's even vaguely unique.
 Can't do this as this happens inside getopt. I pass getopt a Nullable and
 later check whether it was actually set by getopt.

Well, with getopt's design, you're pretty much stuck either using uint (and assuming that 0 means that nothing was set or just use 0 as the default for whatever you're doing), or you have to take the string and do what you want to yourself. It's just not designed to distinguish between an option not being set and it being set to the default. I suppose as an alternative, you could use a floating point type and if it's not NaN, test to make sure that the result is an integral. I suppose that a possible solution to the design issue with getopt would be to make it special-case Nullable so that you'd get the behavior that you're looking for. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #8 from jens.k.mueller gmx.de 2013-01-09 04:07:20 PST ---
(In reply to comment #7)
 Why is it impossible to make isIntegral work for user-defined types in the 
 same way as e.g. isInputRange works?
 They do have an API. Just to mention some you use +, -, *, / etc. You just 
 need to fix this set.

Because those operations aren't unique to integral types. They're not even necessarily unique to _numeric_ types. Input ranges have fairly a unique API, so you can test for it, but integral types don't have an API that's even vaguely unique.

I believe the set of operations is unique. But I would need to try it out. Do you happen to know of an example that supports the set of integral oprations yet is no integral?
 Can't do this as this happens inside getopt. I pass getopt a Nullable and
 later check whether it was actually set by getopt.

Well, with getopt's design, you're pretty much stuck either using uint (and assuming that 0 means that nothing was set or just use 0 as the default for whatever you're doing), or you have to take the string and do what you want to yourself. It's just not designed to distinguish between an option not being set and it being set to the default. I suppose as an alternative, you could use a floating point type and if it's not NaN, test to make sure that the result is an integral. I suppose that a possible solution to the design issue with getopt would be to make it special-case Nullable so that you'd get the behavior that you're looking for.

Yah. Same here. I will look for a way to fix this in my code. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286


jens.k.mueller gmx.de changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID


-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 09 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #9 from Jonathan M Davis <jmdavisProg gmx.com> 2013-01-09 04:12:00
PST ---
 I believe the set of operations is unique. But I would need to try it out. Do
 you happen to know of an example that supports the set of integral oprations
 yet is no integral?

Floating point types support exactly the same set of operations as integral types but with slightly different semantics. So, there's no way to test a type's API for being an integral type without floating point types matching as well. Also, would types like core.time.Duration or core.time.TickDuration count as integral types? Both of them support those operations, and yet I wouldn't consider them to be integral types. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9286



--- Comment #10 from jens.k.mueller gmx.de 2013-01-09 06:03:30 PST ---
(In reply to comment #9)
 I believe the set of operations is unique. But I would need to try it out. Do
 you happen to know of an example that supports the set of integral oprations
 yet is no integral?

Floating point types support exactly the same set of operations as integral types but with slightly different semantics. So, there's no way to test a type's API for being an integral type without floating point types matching as well.

True. Floating point types shouldn't be counted as integral. Then let's check for these semantics. What about 1 / T.max == 0? Admittedly this requires CTFE of your type. You're right that you may also need to consider the semantics of the operations.
 Also, would types like core.time.Duration or core.time.TickDuration count
 as integral types? Both of them support those operations, and yet I wouldn't
 consider them to be integral types.

No, since division must return a T. But a duration needs to loose its unit when dividing. -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
Jan 09 2013