[Pitch] Ban the top value in Int/UInt

在 2016年10月19日,11:43,Kevin Nattinger <swift@nattinger.net> 写道:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

I’ve only needed an array of optionals once, maybe twice. I don’t think arrays of optionals are widely used to begin with, and the reason there are few optional integers in the stdlib is because the interface is from objc, which doesn’t have optionals. I doubt any thought at all was given in designing the standard library to the extra space for an optional.

Swift stdlib is independent from objc. Currently, "Int?" storage has a tradeoff between less space (n + 1 bytes) and unaligned access, and more space (n * 2 bytes) and fast access. Neither of them is optimal.

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Well the “top value” for signed ints would have to be 0x8000... not 0xffff... which is the representation of -1. The top value for unsigned ints cannot be banned because unsigned integers are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in compatible bit patterns. Now that I think of it, UInt is commonly used for bitwise operations, and it doesn't make sense to optimize for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

In my experience, ints are used orders of magnitude more often than optional int?s. Why optimize for the rare case?

If we were to have safe arithmetic that produces optionals, or lenient subscript, it is important to have efficient optional integers. I do agree that Int slowing down is unacceptable.

- Guoye

···

On Oct 19, 2016, at 8:13 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

Int? is an enum wrapping an integer, why wouldn’t you expect it to be bigger than an Int? I honestly don’t get why this is suddenly a huge problem. If you are working in a situation where you need an in memory array of ~billion Ints, I agree it becomes an issue but there’s nothing stopping you from implementing the convention manually for that one application.

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Well the “top value” for signed ints would have to be 0x8000... not 0xffff... which is the representation of -1. The top value for unsigned ints cannot be banned because unsigned integers are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in compatible bit patterns. Now that I think of it, UInt is commonly used for bitwise operations, and it doesn't make sense to optimize for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

I wouldn’t want to trade Int performance off against Int? performance. I think the former is much more common.

So what do you think? Can we break C compatibility a bit for better Swift types?

Well it’s not just C compatibility, it’s underlying processor compatibility. And actually, yes, I think C compatibility is vastly more important than being able to make your [Int?] arrays smaller considering that full 2’s complement numbers is what the OS calls and libc calls are expecting.

Yes, that is also the result Joe said of their previous internal discussion. Anyway, I know this is improbable, and I'm just glad that this possibility is considered.

I agree that it’s important to discuss these ideas. When you proposed this, my first reaction was “this is crazy” but reading the rationale and other posts, made me realise that my reaction was almost just a reflexive reaction along the lines of “it’s always been this way, why change?”. Your post forced me to sit down and think about why it should or shouldn’t be implemented in Swift. As you can see, my final position didn’t change, but you made me think and whichever way the discussion eventually goes, that’s a good thing.

···

On 19 Oct 2016, at 16:13, Guoye Zhang <cc941201@me.com> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

- Guoye

Personally I prefer the way Optionals currently work (add one bit), but I think a better compromise would be the ability to specify arbitrary width integers.

For example, I have a type that stores an optional (so 1-bit overhead) and I want to store less than a byte of extra data; if I could specify a 7-bit integer then I could limit overhead to a single byte, but currently cannot (at least, not without using single Bools which I don't want to do.

For collections there may be other options; for example, storing the optionality of values in a separate bitmap, which would reduce memory overhead, perhaps types could be added that can do this? For storing lots of optionals this would be more efficient on memory, with a slight overhead for double optionality checking. Here's a quick example of what I mean:

struct OptionalArray<T> : Collection {
    var values:[T] = , bitmap:[Bool] = , defaultValue:T

    init(defaultValue:T) { self.defaultValue = defaultValue }
    init<S:Sequence>(_ theElements:S, defaultValue:T) where S.Iterator.Element == T? {
        self.defaultValue = defaultValue

        self.values.reserveCapacity(theElements.underestimatedCount)
        self.bitmap.reserveCapacity(theElements.underestimatedCount)

        for eachElement in theElements {
            self.values.append(eachElement ?? defaultValue)
            self.bitmap.append(eachElement != nil)
        }
    }

    var count:Int { return self.values.count }

    var startIndex:Int { return self.values.startIndex }
    var endIndex:Int { return self.values.endIndex }

    func formIndex(after i:inout Int) { self.values.formIndex(after: &i) }
    func index(after i:Int) -> Int { return self.values.index(after: i) }

    subscript(index:Int) -> T? {
        get { return self.bitmap[index] ? self.values[index] : nil }
        set { self.values[index] = newValue ?? self.defaultValue }
    }
}

You could easily adapt this to store optionality using a default value that's unlikely to occur, like so:

struct OptionalArrayAlt<T:Equatable> : Collection {
    var values:[T] = , defaultValue:T

    init(defaultValue:T) { self.defaultValue = defaultValue }
    init<S:Sequence>(_ theElements:S, defaultValue:T) where S.Iterator.Element == T? {
        self.defaultValue = defaultValue
        values.reserveCapacity(theElements.underestimatedCount)
        self.values = theElements.map { return $0 ?? defaultValue }
    }

    var count:Int { return self.values.count }

    var startIndex:Int { return self.values.startIndex }
    var endIndex:Int { return self.values.endIndex }

    func formIndex(after i:inout Int) { self.values.formIndex(after: &i) }
    func index(after i:Int) -> Int { return self.values.index(after: i) }

    subscript(index:Int) -> T? {
        get { let value = self.values[index]; return value == self.defaultValue ? value : nil }
        set { self.values[index] = newValue ?? self.defaultValue }
    }
}

With the caveat that you either can't store values equal to defaultValue (they become nil) or add an assertion/error if that value is stored.

But yeah, I don't think that rolling out the idea to all optionals is a good idea; the biggest gains will be had in collections, so any efforts should be focused there IMO, and on making custom types align better if possible.

···

On 18 Oct 2016, at 21:32, Jean-Daniel via swift-evolution <swift-evolution@swift.org> wrote:

Le 18 oct. 2016 à 21:09, Charlie Monroe via swift-evolution <swift-evolution@swift.org> a écrit :

Talking about bridging - my guess is that it would mess with NSNotFound which still has legit use cases even in Swift (when dealing with ObjC APIs) and is defined as NSIntegerMax at this moment, though its usage is slowly on the decline…

Bridge the API that may return NSNotFound to return optional. It would work perfectly well as the nil optional and NSNotFound would have the same binary representation.

But there are still many many APIs (mostly C-based) that define some "magic" constants as (unsigned)(-1), which I believe this would mess with.

Given this, it would IMHO have huge consequences for backward compatiblity.

On Oct 18, 2016, at 8:54 PM, Kevin Nattinger via swift-evolution <swift-evolution@swift.org> wrote:

Part of the beauty of how optionals are implemented in Swift is that the compiler doesn’t have to do any magic w.r.t. optionals besides a bit of syntactic sugar (`T?` -> `Optional<T>`, `if let x` -> `if let case .some(x)`, auto-boxing when necessary, etc.).
- I strongly dislike the idea of special-casing optionals just to save a Byte.
- Optionals were presented as explicitly removing the need for such a sentinel value in the first place.
- There are reasonable cases where such a bit pattern is reasonably necessary to the data (e.g. bit fields, RSSI, IP addresses, etc.) and removing that value would force ugly workarounds and/or moving to a larger int size because of an ill-advised implementation detail.
- If performance or memory is so critical to your specific use case, use a non-optional and your own sentinel value. It’s likely no less efficient than having the compiler do it that way.

(more below)

On Oct 18, 2016, at 11:17 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Interacting with C/Obj-C is a major concern, but since we are already importing some of the unsigned integers as Int which loses half the values,

I’d argue those imports are bugs and should be fixed to the correct signedness.

one value is not such big a drawback.

Unless you happen to need all $width bits.

Alternatively, we could leave current behavior as CInt/CUInt. Converting them to the new Int?/UInt? doesn't generate any instructions since the invalid value already represents nil.

Trying to convert an invalid value like that crashes in most of Swift.

With optional integers improved, we could implement safe arithmetic efficiently, or even revisit lenient subscript proposals,

I don’t see how losing a particular value has any effect on either of those, but it’s possible there’s some theory or implementation detail I’m not aware of.

but they are not in the scope of this pitch. Float/Double optionals could also be improved with the similar idea. (Isn't signaling nan the same as nil) Nested optionals such as "Int??" are still bloated, but I don't think they are widely used.

So what do you think? Can we break C compatibility a bit for better Swift types?

We can, and do. C.f. structs, non-@objc classes, and enums not RawRepresentable with a C-compatible entity. If anything, this breaks compatibility with the rest of Swift.

- Guoye
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

在 2016年10月19日,11:43,Kevin Nattinger <swift@nattinger.net> 写道:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

I’ve only needed an array of optionals once, maybe twice. I don’t think arrays of optionals are widely used to begin with, and the reason there are few optional integers in the stdlib is because the interface is from objc, which doesn’t have optionals. I doubt any thought at all was given in designing the standard library to the extra space for an optional.

Swift stdlib is independent from objc. Currently, "Int?" storage has a tradeoff between less space (n + 1 bytes) and unaligned access, and more space (n * 2 bytes) and fast access. Neither of them is optimal.

Something worth considering at a higher level is whether Array ought to align storage at all. Modern Intel and Apple CPUs pay much less of a penalty for unaligned access than older microarchitectures, and the memory savings of packing arrays of Int? and similar types would be significant. (There are C compatibility issues here too, since C's semantic model requires pointers to be well-aligned for their type, and we want Swift.Arrays of C types to be cheaply interoperable with pointer-based C APIs. This could perhaps be dealt with by guaranteeing that C basic types and structs always have sizeof(T) % alignof(T) == 0, and well-aligning the beginning of arrays.)

-Joe

···

On Oct 19, 2016, at 9:16 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 19, 2016, at 8:13 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Well the “top value” for signed ints would have to be 0x8000... not 0xffff... which is the representation of -1. The top value for unsigned ints cannot be banned because unsigned integers are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in compatible bit patterns. Now that I think of it, UInt is commonly used for bitwise operations, and it doesn't make sense to optimize for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

In my experience, ints are used orders of magnitude more often than optional int?s. Why optimize for the rare case?

If we were to have safe arithmetic that produces optionals, or lenient subscript, it is important to have efficient optional integers. I do agree that Int slowing down is unacceptable.

- Guoye
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

在 2016年10月19日,11:43,Kevin Nattinger <swift@nattinger.net> 写道:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact
representations that utilize all available values, which is
inherited from C. However, it is horribly inefficient to
implement optional integers. It takes double the space to store
[Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space
seems inefficient. I guess this is also the reason why they didn't
adopt optional integers widely in stdlib.

I’ve only needed an array of optionals once, maybe twice. I don’t
think arrays of optionals are widely used to begin with, and the
reason there are few optional integers in the stdlib is because the
interface is from objc, which doesn’t have optionals. I doubt any
thought at all was given in designing the standard library to the
extra space for an optional.

Swift stdlib is independent from objc. Currently, "Int?" storage has
a tradeoff between less space (n + 1 bytes) and unaligned access,
and more space (n * 2 bytes) and fast access. Neither of them is
optimal.

Something worth considering at a higher level is whether Array ought
to align storage at all. Modern Intel and Apple CPUs pay much less of
a penalty for unaligned access than older microarchitectures, and the
memory savings of packing arrays of Int? and similar types would be
significant.

The only way to do that without breaking language rules would be to
redefine the alignment of those types to be 1. It would require no
changes to the standard library.

···

on Wed Oct 19 2016, Joe Groff <swift-evolution@swift.org> wrote:

On Oct 19, 2016, at 9:16 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 19, 2016, at 8:13 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

(There are C compatibility issues here too, since C's semantic model
requires pointers to be well-aligned for their type, and we want
Swift.Arrays of C types to be cheaply interoperable with pointer-based
C APIs. This could perhaps be dealt with by guaranteeing that C basic
types and structs always have sizeof(T) % alignof(T) == 0, and
well-aligning the beginning of arrays.)

-Joe

I propose to ban the top value in Int/UInt which is 0xFFFF... in
hex. Int family would lose its smallest value, and UInt family
would lose its largest value. Top value is reserved for nil in
optionals. An additional benefit is that negating an Int would
never crash.

Well the “top value” for signed ints would have to be
0x8000... not 0xffff... which is the representation of -1. The
top value for unsigned ints cannot be banned because unsigned
integers are often used as bit fields either directly or in
OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in
compatible bit patterns. Now that I think of it, UInt is commonly
used for bitwise operations, and it doesn't make sense to optimize
for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

In my experience, ints are used orders of magnitude more often than optional int?s. Why optimize for the rare case?

If we were to have safe arithmetic that produces optionals, or
lenient subscript, it is important to have efficient optional
integers. I do agree that Int slowing down is unacceptable.

- Guoye
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
-Dave

在 2016年10月19日,12:21,Joe Groff <jgroff@apple.com> 写道:

在 2016年10月19日,11:43,Kevin Nattinger <swift@nattinger.net> 写道:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

I’ve only needed an array of optionals once, maybe twice. I don’t think arrays of optionals are widely used to begin with, and the reason there are few optional integers in the stdlib is because the interface is from objc, which doesn’t have optionals. I doubt any thought at all was given in designing the standard library to the extra space for an optional.

Swift stdlib is independent from objc. Currently, "Int?" storage has a tradeoff between less space (n + 1 bytes) and unaligned access, and more space (n * 2 bytes) and fast access. Neither of them is optimal.

Something worth considering at a higher level is whether Array ought to align storage at all. Modern Intel and Apple CPUs pay much less of a penalty for unaligned access than older microarchitectures, and the memory savings of packing arrays of Int? and similar types would be significant. (There are C compatibility issues here too, since C's semantic model requires pointers to be well-aligned for their type, and we want Swift.Arrays of C types to be cheaply interoperable with pointer-based C APIs. This could perhaps be dealt with by guaranteeing that C basic types and structs always have sizeof(T) % alignof(T) == 0, and well-aligning the beginning of arrays.)

-Joe

That would be great, and certainly needs exploring before locking ABI.

- Guoye

···

On Oct 19, 2016, at 9:16 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On Oct 19, 2016, at 8:13 AM, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Well the “top value” for signed ints would have to be 0x8000... not 0xffff... which is the representation of -1. The top value for unsigned ints cannot be banned because unsigned integers are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in compatible bit patterns. Now that I think of it, UInt is commonly used for bitwise operations, and it doesn't make sense to optimize for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

In my experience, ints are used orders of magnitude more often than optional int?s. Why optimize for the rare case?

If we were to have safe arithmetic that produces optionals, or lenient subscript, it is important to have efficient optional integers. I do agree that Int slowing down is unacceptable.

- Guoye
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

在 2016年10月20日,05:45,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

在 2016年10月19日,07:10,Jeremy Pereira <jeremy.j.pereira@googlemail.com> 写道:

Currently, Swift Int family and UInt family have compact representations that utilize all available values, which is inherited from C. However, it is horribly inefficient to implement optional integers. It takes double the space to store [Int?] than to store [Int] because of alignment.

Is this a general problem with Swift? Are lots of people complaining that they are running out of space for their Optional<Int> arrays?

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

Int? is an enum wrapping an integer, why wouldn’t you expect it to be bigger than an Int? I honestly don’t get why this is suddenly a huge problem. If you are working in a situation where you need an in memory array of ~billion Ints, I agree it becomes an issue but there’s nothing stopping you from implementing the convention manually for that one application.

MemoryLayout<AnyObject????>.size is the same as MemoryLayout<AnyObject>.size because there are invalid addresses in pointers that Swift compiler can use to represent nil.

I propose to ban the top value in Int/UInt which is 0xFFFF... in hex. Int family would lose its smallest value, and UInt family would lose its largest value. Top value is reserved for nil in optionals. An additional benefit is that negating an Int would never crash.

Well the “top value” for signed ints would have to be 0x8000... not 0xffff... which is the representation of -1. The top value for unsigned ints cannot be banned because unsigned integers are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in compatible bit patterns. Now that I think of it, UInt is commonly used for bitwise operations, and it doesn't make sense to optimize for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

I wouldn’t want to trade Int performance off against Int? performance. I think the former is much more common.

Slowing down Int is never my intent. I hope to have Int? that gives on par performance with Int, and the possibility to have safe arithmetics that doesn't impose overhead.

- Guoye

···

On 19 Oct 2016, at 16:13, Guoye Zhang <cc941201@me.com> wrote:

On 18 Oct 2016, at 19:17, Guoye Zhang via swift-evolution <swift-evolution@swift.org> wrote:

Hello,

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

When someone is really interested in fitting an optional integer into one machine word,
then the best way would be to use a smaller integer type (e.g. Int32 instead of Int64).
These also can be mapped well into Enums (a single reserved value does not help at all here).

There are some almost 64-bit integers (Builtin.Int60 .. Builtin.Int63).
Maybe something like this could also be provided for normal use?

···

--
Martin

This is supported by LLVM and exposed through the low-level 'Builtin' module in Swift, though the standard library doesn't expose it to user code. If you define an enum { case Foo(Builtin.Int63), Bar }, Swift already knows how to use the spare bits in an Int63 to avoid spilling extra tag bits.

-Joe

···

On Oct 20, 2016, at 8:25 AM, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 20 Oct 2016, at 15:51, Martin Waitz via swift-evolution <swift-evolution@swift.org> wrote:

Hello,

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

When someone is really interested in fitting an optional integer into one machine word,
then the best way would be to use a smaller integer type (e.g. Int32 instead of Int64).
These also can be mapped well into Enums (a single reserved value does not help at all here).

There are some almost 64-bit integers (Builtin.Int60 .. Builtin.Int63).
Maybe something like this could also be provided for normal use?

I mentioned earlier, but it'd be nice to see the ability to specify arbitrary width integers up to the word size. I myself have a type where I could more efficiently use a 7-bit integer, to offset the extra bit for an optional, but currently have to just use a byte (or else use some kind of awkward trickery). Presumably all of the weird builtin sizes are implemented somehow to as 64-bit operations, it's just the size that differs.

I'm not very knowledgeable on the subject though, so I'm not sure if I'd be the best person to write up a proposal, though I could always keep it high level.

Hello,

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

When someone is really interested in fitting an optional integer into one machine word,
then the best way would be to use a smaller integer type (e.g. Int32 instead of Int64).
These also can be mapped well into Enums (a single reserved value does not help at all here).

There are some almost 64-bit integers (Builtin.Int60 .. Builtin.Int63).
Maybe something like this could also be provided for normal use?

I mentioned earlier, but it'd be nice to see the ability to specify arbitrary width integers up to the word size. I myself have a type where I could more efficiently use a 7-bit integer, to offset the extra bit for an optional, but currently have to just use a byte (or else use some kind of awkward trickery). Presumably all of the weird builtin sizes are implemented somehow to as 64-bit operations, it's just the size that differs.

I'm not very knowledgeable on the subject though, so I'm not sure if I'd be the best person to write up a proposal, though I could always keep it high level.

Conceptually, if we ever get around to allowing literals as generic parameters and default values for generic parameters, I don't think it would be too hard to write something like
    struct Int<Width: IntegerLiteral = 64> {...}
and have it generally perform as well as `Int` does now, just by sign-extending the bits to the next available CPU-native size when the value is loaded from memory. The exception is that if `Width` isn't a power of two (and >= 8) we'd have to do our own overflow checking, since CPUs only handle 8/16/32/64-bit ints. I *think* this only has to be done when the value is stored back into system memory... If the value stays overflown, it'd be caught when stored back to RAM, if it comes back down it'll have the correct answer despite temporarily needing a extra few bits (kinda like 80-bit floats), and if it overflows the native CPU type we haven't lost anything over the current approach. I haven't given it more thought than it took to write that out, though... I could easily be missing something (the location of the overflow exception, for example, could be relatively distant from where the "fauxverflow" happened... annoying for debuggers, but I don't think it matters once the code is working).

Personally, I'd be in favor of a note in the docs indicating that there's a slight speed hit from using non-"powers of two" widths, and letting develop decide if it's more important for them to prioritize memory use over absolute performance. Especially since one of the big hurdles of performance-critical is waiting on RAM anyway.

On a purely speculative note, the overflow-checking penalty would go away if CPUs get hardware support for oddly sized ints. Some of Intels newer CPUs (starting with Sky Lake's predecessor, IIRC) have instructions specifically to speed up BigNums, so I don't think it's so "out there" to think they might start including instructions for "LittleNums"

- Dave Sweeris

···

Sent from my iPhone

On Oct 20, 2016, at 10:25, Haravikk via swift-evolution <swift-evolution@swift.org> wrote:

On 20 Oct 2016, at 15:51, Martin Waitz via swift-evolution <swift-evolution@swift.org> wrote:

I mentioned earlier, but it'd be nice to see the ability to specify arbitrary width integers up to the word size. I myself have a type where I could more efficiently use a 7-bit integer, to offset the extra bit for an optional, but currently have to just use a byte (or else use some kind of awkward trickery). Presumably all of the weird builtin sizes are implemented somehow to as 64-bit operations, it's just the size that differs.

I'm not very knowledgeable on the subject though, so I'm not sure if I'd be the best person to write up a proposal, though I could always keep it high level.

···

On 20 Oct 2016, at 15:51, Martin Waitz via swift-evolution <swift-evolution@swift.org> wrote:

Hello,

It's just that a common data type wasting almost half the space seems inefficient. I guess this is also the reason why they didn't adopt optional integers widely in stdlib.

When someone is really interested in fitting an optional integer into one machine word,
then the best way would be to use a smaller integer type (e.g. Int32 instead of Int64).
These also can be mapped well into Enums (a single reserved value does not help at all here).

There are some almost 64-bit integers (Builtin.Int60 .. Builtin.Int63).
Maybe something like this could also be provided for normal use?

Swift arithmetic is already safe.

···

on Thu Oct 20 2016, Guoye Zhang <swift-evolution@swift.org> wrote:

I propose to ban the top value in Int/UInt which is 0xFFFF... in
hex. Int family would lose its smallest value, and UInt family
would lose its largest value. Top value is reserved for nil in
optionals. An additional benefit is that negating an Int would
never crash.

Well the “top value” for signed ints would have to be
0x8000... not 0xffff... which is the representation of -1. The top
value for unsigned ints cannot be banned because unsigned integers
are often used as bit fields either directly or in OptionSets.

Furthermore, how would the semantics of &+ and &- be affected? What
about the performance of those two operators?

I was originally going for the symmetry between Int and UInt as in
compatible bit patterns. Now that I think of it, UInt is commonly
used for bitwise operations, and it doesn't make sense to optimize
for "UInt?" which is uncommon. So I agree that 0x80... is better.

Int performance would surely suffer because of current instruction sets, but Int? would improve.

I wouldn’t want to trade Int performance off against Int?
performance. I think the former is much more common.

Slowing down Int is never my intent. I hope to have Int? that gives on
par performance with Int, and the possibility to have safe arithmetics
that doesn't impose overhead.

--
-Dave