Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-3970] Rework ExpressibleBy(Integer|Float)Literal protocols #46555

Closed
DougGregor opened this issue Feb 15, 2017 · 5 comments
Closed

[SR-3970] Rework ExpressibleBy(Integer|Float)Literal protocols #46555

DougGregor opened this issue Feb 15, 2017 · 5 comments
Assignees
Labels
affects ABI Flag: Affects ABI compiler The Swift compiler in itself duplicate Resolution: Duplicates another issue feature A feature request or implementation improvement standard library Area: Standard library umbrella swift evolution proposal needed Flag → feature: A feature that warrants a Swift evolution proposal

Comments

@DougGregor
Copy link
Member

Previous ID SR-3970
Radar rdar://problem/31419826
Original Reporter @DougGregor
Type Improvement
Status Resolved
Resolution Duplicate
Additional Detail from JIRA
Votes 0
Component/s
Labels Improvement, AffectsABI, StarterProposal
Assignee @hartbit
Priority Medium

md5: 6995ebdcce03aa3a38889089bb6d4141

duplicates:

  • SR-920 Re-design builtin compiler protocols for literal convertible types

relates to:

  • SR-3317 Literal protocol for decimal literals should support precise decimal accuracy
  • SR-7124 Double-rounding in floating-point literal conversion

Issue Description:

The ExpressibleByIntegerLiteral and ExpressibleByFloatLiteral protocols have a number of problems that should be addressed by a redesign:

  • They don't support arbitrary-precision integer/floating point, so (for example) you cannot create a properly-working BigNum type that conforms to ExpressibleByIntegerLiteral. We need a better way to provide the raw integer values.

  • Their fallback to "builtin" types is weird and doesn't make sense; the _Builtin versions of these protocols shouldn't be needed

  • It probably makes sense for ExpressibleByFloatLiteral to inherit ExpressibleByIntegerLiteral

@hartbit
Copy link
Collaborator

hartbit commented Mar 9, 2017

@DougGregor

Ok, I might really not be the best person to tackle this problem, but here we go:

  • What's the magic behind `ExpressibleByIntegerLiteral.IntegerLiteralType` and `ExpressibleByFloatLiteral.FloatLiteralType` that force it to specific Standard Library types?

  • What are their place in the reworked Expressible* protocols?

  • Is that what you mean in the description when you say "Their fallback to "builtin" types is weird and doesn't make sense"?

  • When you say: "the _Builtin versions of these protocols shouldn't be needed", what versions are you talking about?

  • What do you think of the very very very rough first ideas:

public protocol ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int32)
    init(sign: FloatingPointSign, significands: [UInt16])
}

extension ExpressibleByIntegerLiteral {
    init(sign: FloatingPointSign, significands: [UInt16]) {
        precondition(significands.count == 1, "Type does not support big numbers")
        let signFactor: Int32 = sign == .minus ? -1 : 1
        self.init(integerLiteral: signFactor * Int32(significands[0]))
    }
}

public protocol ExpressibleByFloatLiteral : ExpressibleByIntegerLiteral {
    init(floatLiteral value: Double)
    init(sign: FloatingPointSign, exponent: Int, significand: Int)
}

extension ExpressibleByFloatLiteral {
    init(sign: FloatingPointSign, exponent: Int, significand: Int) {
        self.init(floatLiteral: Double(
            sign: sign,
            exponent: exponent,
            significand: Double(significand)))
    }
}
  • associated types were getting so much in my way that I started prototyping with built-in types. Let me know if you have any ideas on what associated types we need.

Here's the big picture:

  • arbitrary-precision integers are supported through a initializer that takes a sign and a list of values such that:
integer = (sign == .minus ? -1 : 1) * (x0 + x1*radix + x2*radix^2 + x3*radix^3 + ...
  • Question: what radix? 2^16? 2^32? 10^N?
  • The compiler transforms literal initialisations to calls to the arbitrary precision initializers `init(sign: FloatingPointSign, significands: [UInt16])` and `init(sign: FloatingPointSign, exponent: Int, significand: Int)` which have default implementations. So, as long as one does not want to bother about the arbitrary precision, types only need to implement the simple initializers.

@DougGregor
Copy link
Member Author

The `init(sign:significands)` approach seems totally reasonable to me; I'd suggest doing roughly the same thing with the `ExpressibleByFloatLiteral` initializer, so we allow arbitrary-precision floats. I do wonder if it's better to just pass an unsafe buffer pointer, because arrays are a bit heavyweight for this part of the system.

Was your intent for the `init(floatLiteral🙂` and `init(integerLiteral🙂` initializers to be there for backward compatibility, or something else?

I think the associated types could go away; they're there so we can do a hack with the builtin types that the Swift compiler recognizes.

@hartbit
Copy link
Collaborator

hartbit commented Mar 28, 2017

> I think the associated types could go away; they're there so we can do a hack with the builtin types that the Swift compiler recognizes.

If they go away, we have to decide on what type init(integerLiteral value: Int) takes as argument. The logic would dictate to go with Int64 so as to support 64bit integer literals. But then, a conforming type that doesn't support 64bit ints would have to resort to a runtime crash to signify it doesn't support them. Example:

enum CSSValue {
    case pixel(Int32)
    case percent(Int32)
}

extension CSSValue : ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int64) {
        self = .pixel(Int(value))
    }
}

Whereas, right now, we can generate a compile time error:

extension CSSValue : ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int32) {
        self = .pixel(value)
    }
}

let value: CSSValue = 9_223_372_036_854_775_807
// error: integer literal '9223372036854775807' overflows when stored into 'Int32'

> Was your intent for the `init(floatLiteral` and `init(integerLiteral` initializers to be there for backward compatibility, or something else?

No, the reasoning was for them to stay for when a conforming type does not require arbitrary precision and wants to implement a simple initializer, hence the default implementations of the arbitrary precision initialiser containing a precondition for significands.count == 1. But we could transform that into a compile time error:

public protocol ExpressibleByIntegerLiteral {
    init(integerLiteral value: Int64)
}

public protocol ExpressibleByArbitraryPrecisionIntegerLiteral {
    init(sign: FloatingPointSign, buffer: UnsafeBufferPointer<Int64>)
}

The compiler would then generate an error when trying to assign an integer literal greater than Int64.max into a type that conforms to ExpressibleByIntegerLiteral but not ExpressibleByArbitraryPrecisionIntegerLiteral.

Thoughts?

@bob-wilson
Copy link

@swift-ci create

@bob-wilson
Copy link

Let's track this as part of SR-920.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@AnthonyLatsis AnthonyLatsis added compiler The Swift compiler in itself swift evolution proposal needed Flag → feature: A feature that warrants a Swift evolution proposal feature A feature request or implementation standard library Area: Standard library umbrella duplicate Resolution: Duplicates another issue and removed StarterProposal labels Nov 11, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects ABI Flag: Affects ABI compiler The Swift compiler in itself duplicate Resolution: Duplicates another issue feature A feature request or implementation improvement standard library Area: Standard library umbrella swift evolution proposal needed Flag → feature: A feature that warrants a Swift evolution proposal
Projects
None yet
Development

No branches or pull requests

4 participants