[swift-evolution] [proposal]Decouple definition of Int8 from target char type

Dmitri Gribenko gribozavr at gmail.com
Fri Feb 26 11:09:51 CST 2016


On Fri, Feb 26, 2016 at 9:01 AM, William Dillon <william at housedillon.com> wrote:
>
>> On Feb 25, 2016, at 11:13 PM, Dmitri Gribenko <gribozavr at gmail.com> wrote:
>>
>> On Thu, Feb 25, 2016 at 9:58 PM, William Dillon <william at housedillon.com> wrote:
>>>>> Swift currently maps the Int8 type to be equal to the char type of the target platform.  On targets where char is unsigned by default, Int8 becomes an unsigned 8-bit integer, which is a clear violation of the Principle of Least Astonishment.  Furthermore, it is impossible to specify a signed 8-bit integer type on platforms with unsigned chars.
>>>>
>>>> I'm probably misunderstanding you, but are you sure that's what is
>>>> happening?  I can't imagine how the standard library would just
>>>> silently make Int8 unsigned on Linux arm.
>>>>
>>>
>>> I think the best way to demonstrate this is through an example.  Here is a sample swift program:
>>>
>>> import Foundation
>>> print(NSNumber(char: Int8.min).shortValue)
>>
>> There is a lot happening in this snippet of code (including importing
>> two completely different implementations of Foundation, and the pure
>> swift one not being affected by Clang importer at all).  Could you
>> provide AST dumps for both platforms for this code?
>>
>
> Of course.  Here’s the AST on ARM:
>
> wdillon at tegra-ubuntu:~$ swiftc -dump-ast example.swift
> (source_file
>   (import_decl 'Foundation')
>   (top_level_code_decl
>     (brace_stmt
>       (call_expr type='()' location=example.swift:2:1 range=[example.swift:2:1 - line:2:42] nothrow
>         (declref_expr type='(Any..., separator: String, terminator: String) -> ()' location=example.swift:2:1 range=[example.swift:2:1 - line:2:1] decl=Swift.(file).print(_:separator:terminator:) specialized=no)
>         (tuple_shuffle_expr implicit type='(Any..., separator: String, terminator: String)' location=example.swift:2:32 range=[example.swift:2:6 - line:2:42] sourceIsScalar elements=[-2, -1, -1] variadic_sources=[0]
>           (paren_expr type='Any' location=example.swift:2:32 range=[example.swift:2:6 - line:2:42]
>             (erasure_expr implicit type='Any' location=example.swift:2:32 range=[example.swift:2:7 - line:2:32]
>               (member_ref_expr type='Int16' location=example.swift:2:32 range=[example.swift:2:7 - line:2:32] decl=Foundation.(file).NSNumber.shortValue
>                 (call_expr type='NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:30] nothrow
>                   (constructor_ref_call_expr type='(char: Int8) -> NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] nothrow
>                     (declref_expr implicit type='NSNumber.Type -> (char: Int8) -> NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] decl=Foundation.(file).NSNumber.init(char:) specialized=no)
>                     (type_expr type='NSNumber.Type' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] typerepr='NSNumber'))
>                   (tuple_expr type='(char: Int8)' location=example.swift:2:15 range=[example.swift:2:15 - line:2:30] names=char
>                     (member_ref_expr type='Int8' location=example.swift:2:27 range=[example.swift:2:22 - line:2:27] decl=Swift.(file).Int8.min
>                       (type_expr type='Int8.Type' location=example.swift:2:22 range=[example.swift:2:22 - line:2:22] typerepr='Int8'))))))))))))
>
> And Darwin:
>
> Falcon:~ wdillon$ xcrun -sdk macosx swiftc -dump-ast example.swift
> (source_file
>   (import_decl 'Foundation')
>   (top_level_code_decl
>     (brace_stmt
>       (call_expr type='()' location=example.swift:2:1 range=[example.swift:2:1 - line:2:42] nothrow
>         (declref_expr type='(Any..., separator: String, terminator: String) -> ()' location=example.swift:2:1 range=[example.swift:2:1 - line:2:1] decl=Swift.(file).print(_:separator:terminator:) specialized=no)
>         (tuple_shuffle_expr implicit type='(Any..., separator: String, terminator: String)' location=example.swift:2:32 range=[example.swift:2:6 - line:2:42] sourceIsScalar elements=[-2, -1, -1] variadic_sources=[0]
>           (paren_expr type='Any' location=example.swift:2:32 range=[example.swift:2:6 - line:2:42]
>             (erasure_expr implicit type='Any' location=example.swift:2:32 range=[example.swift:2:7 - line:2:32]
>               (member_ref_expr type='Int16' location=example.swift:2:32 range=[example.swift:2:7 - line:2:32] decl=Foundation.(file).NSNumber.shortValue
>                 (call_expr type='NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:30] nothrow
>                   (constructor_ref_call_expr type='(char: Int8) -> NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] nothrow
>                     (declref_expr implicit type='NSNumber.Type -> (char: Int8) -> NSNumber' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] decl=Foundation.(file).NSNumber.init(char:) specialized=no)
>                     (type_expr type='NSNumber.Type' location=example.swift:2:7 range=[example.swift:2:7 - line:2:7] typerepr='NSNumber'))
>                   (tuple_expr type='(char: Int8)' location=example.swift:2:15 range=[example.swift:2:15 - line:2:30] names=char
>                     (member_ref_expr type='Int8' location=example.swift:2:27 range=[example.swift:2:22 - line:2:27] decl=Swift.(file).Int8.min
>                       (type_expr type='Int8.Type' location=example.swift:2:22 range=[example.swift:2:22 - line:2:22] typerepr='Int8')))))))))))
>
> I want to point out that these are identical, as far as I can tell.

I agree.  Then, the difference in behavior should be contained in the
NSNumber implementation.  As far as this piece of code is concerned,
it correctly passes the value as Int8.  Could you debug what's
happening in the corelibs Foundation, to find out why it is not
printing a negative number?

> As another exercise, you can tell clang to use signed or unsigned chars and there will be no change:
>
> wdillon at tegra-ubuntu:~$ swiftc example.swift  -Xcc -funsigned-char
> wdillon at tegra-ubuntu:~$ ./example
> 128
> wdillon at tegra-ubuntu:~$ swiftc example.swift  -Xcc -fsigned-char
> wdillon at tegra-ubuntu:~$ ./example
> 128

And it makes sense, since the program you provided does not compile
any C code.  It is pure-swift (though it calls into C via corelibs
Foundation).

>>>> What about a proposal where we would always map 'char' to Int8,
>>>> regardless of the C's idea of signedness?
>>>>
>>>
>>> In a very real sense this is exactly what is happening currently.
>>
>> Sorry, I don't see that yet -- it is still unclear to me what is happening.
>>
>
> That’s ok.  We’ll keep working on it until I’ve proven to everyone’s satisfaction that there really is a problem.

Given what you showed with corelibs Foundation, I agree there's a
problem.  I'm just trying to understand how much of that behavior was
intended, if there are any bugs in the compiler (in implementing our
intended behavior), if there are any bugs in Foundation, and what
would the behavior be if we fixed those bugs.  When we have that, we
can analyze our model (as-if it was implemented as intended) and make
a judgement whether it works, and whether is a good one.

For example, if it turns out that the issue above is due to a bug in
the C parts of CoreFoundation that assumes signed char on arm (because
of iOS, say), then there's nothing that a language change in Swift
could do.

Dmitri

-- 
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/


More information about the swift-evolution mailing list