[swift-evolution] [Pitch] Constrains for numeric types: Int<1...10> Double<0.0...1.0>

Vladimir.S svabox at gmail.com
Wed May 18 12:58:51 CDT 2016


On 18.05.2016 20:28, Krystof Vasa wrote:
> Or just $0 as in closures or newValue as in setters?

Yes, seems like the good idea

var alpha: Double where $0 >= 0.0
or
var alpha: Double where newValue >= 0.0

> BTW this proposal would be simpler to implement IMHO, since the following code:
>
> var user: MNUser where #statement
>
> Would just become
>
> var user: MNUser {
>     didSet { assert(#statement) }
> }

I believe we should be still able to use did/willSet for such 
variables/properties, right? :

var alpha: Double where $0 >= 0.0 {didSet { updateAll() } }

> And with regular arguments, these assertions would get prepended to the funtion body.
>
> It would get a bit more complicated were this on protocols:
>
> protocol MyProtocol {
>    var alpha: Double where alpha >= 0.0 { get set }
> }

Probably we should not to try to move this feature to protocols?

>
>
> 18. 5. 2016 v 19:18, Vladimir.S via swift-evolution <swift-evolution at swift.org>:
>
>> Also though about this. As for numbers, this could be used:
>>
>> var alpha: Double where (0.0...1.0).contains(alpha)
>>
>> or
>>
>> var value: Int where value.isIn(0..<100)
>>
>> if we have
>>
>> extension Int {
>>    func isIn(i: HalfOpenInterval<Int>)->Bool {
>>        return i.contains(self)
>>    }
>> }
>> (it is sad that we can't use `in` name for such function)
>>
>> But I don't like here repeats of the name of variable/property. In case small names it is OK, but when we use someDescriptiveName - I don't want to repeat them and IMO any repeat is a possibility for error(when you by mistake typed other name). So probably I'd like something like placeholder #it for the same name:
>>
>> var user: MNUser where #it.isLoggedIn
>>
>>
>>
>>> On 18.05.2016 19:34, Krystof Vasa via swift-evolution wrote:
>>> How about something like this instead? Seems a bit more general and perhaps
>>> more useful (though with numbers it's not as elegant)?
>>>
>>> var alpha: Double where alpha >= 0.0 && alpha <= 0.0
>>> var user: MNUser where user.isLoggedIn
>>> var name: String where !name.isEmpty
>>>
>>> Krystof
>>>
>>>> On May 18, 2016, at 2:49 PM, Adrian Zubarev via swift-evolution
>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>>
>>>> As you guys brought my idea back to life and I’ve done some effort of
>>>> digging into the Swifts generic future I can show you some fresh ideas.
>>>>
>>>> `Refinement Types` could be really handy, but put them aside for a moment.
>>>>
>>>> Actually we could achieve something like Int<minValue, maxValue> in Swift
>>>> 3. Take a look at this section
>>>> here: https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#generic-value-parameters
>>>>
>>>> There is a slightly problem with this, we cannot rewrite all types to be
>>>> generic with default parameters. That said it would be nice if we could
>>>> overload types somehow (Int vs. Int<Range>), but I’m not sure if this
>>>> idea would suit the language like this.
>>>>
>>>> Anyways we could then have:
>>>>
>>>> struct Int<_ range: Range<Int>> { … }
>>>>
>>>> Sadly this makes the type not safe at compile time but only signals the
>>>> user that at runtime you can’t use any number our of its range.
>>>>
>>>> --
>>>> Adrian Zubarev
>>>> Sent with Airmail
>>>>
>>>> Am 18. Mai 2016 bei 14:13:09, Vladimir.S via swift-evolution
>>>> (swift-evolution at swift.org <mailto:swift-evolution at swift.org>) schrieb:
>>>>
>>>>>> I generally think it’s a cool idea and that it can be useful in minimizing
>>>>>> partial functions by requiring that these cases are explicitly handled.
>>>>>
>>>>> Support this opinion.
>>>>>
>>>>> Other example where such feature could be useful: some public property in
>>>>> type that can accept values from some interval. For example we have class
>>>>> with transparency property that can be 0.0 ... 0.1:
>>>>>
>>>>> class MyShape {
>>>>> public var transparency: Double = 1.0 // 0.0 ... 0.1
>>>>> }
>>>>>
>>>>> yes, we can use willSet/didSet to check this every time. But if we have a
>>>>> number of such properties, we have a lot of repetitive and boilerplate code:
>>>>>
>>>>> class C {
>>>>> var transparancy : Double = 1.0 {
>>>>> didSet { check(transparancy, 0.0...1.0) }
>>>>> }
>>>>>
>>>>> var prop1 : Int = 1 {
>>>>> didSet { check(prop1, from: -10...10) }
>>>>> }
>>>>>
>>>>> var prop2 : Int = 1 {
>>>>> didSet { check(prop2, from: 0...100) }
>>>>> }
>>>>> }
>>>>>
>>>>> , and all will be worse if we also need didSet observers to do some
>>>>> 'useful' work here.
>>>>> Proposed solution will looks like:
>>>>>
>>>>> class C {
>>>>> var transparancy : Double<0.0...1.0> = 1.0
>>>>>
>>>>> var prop1 : Int<-10...10> = 1
>>>>>
>>>>> var prop2 : Int<0...100> = 1
>>>>> }
>>>>>
>>>>> Probably the alternative could be some kind of `where` or `bounded` clause
>>>>> for numeric types and arguments:
>>>>>
>>>>> class C {
>>>>> var transparancy : Double = 1.0 where 0.0...1.0
>>>>> //var transparancy : Double bounded 0.0...1.0 = 1.0
>>>>>
>>>>> var prop1 : Int = 1 where -10...10
>>>>>
>>>>> var prop2 : Int = 1 where 0.0...1.0
>>>>>
>>>>> //var prop3 : Float bounded 0.0..<100.0 = 0.0
>>>>> }
>>>>>
>>>>>
>>>>> On 18.05.2016 11:30, David Rönnqvist via swift-evolution wrote:
>>>>>> It reminds me of "Refinement Types" (see for example [this blog post][1] or
>>>>>> [this paper][2]).
>>>>>>
>>>>>> I generally think it’s a cool idea and that it can be useful in minimizing
>>>>>> partial functions by requiring that these cases are explicitly handled.
>>>>>> For example, highlighting that the following `average` implementation
>>>>>> divides by zero when the list is empty:
>>>>>>
>>>>>> func average(numbers: [Int]) -> Int {
>>>>>> return sum(numbers) / numbers.count
>>>>>> }
>>>>>>
>>>>>>
>>>>>> and requiring that the empty list case is handled separately:
>>>>>>
>>>>>> func average(numbers: [Int]) -> Int {
>>>>>> guard !numbers.isEmpty else { return 0 }
>>>>>> return sum(numbers) / numbers.count
>>>>>> }
>>>>>>
>>>>>>
>>>>>> Regards,
>>>>>> David
>>>>>>
>>>>>> [1]: http://goto.ucsd.edu/~rjhala/liquid/haskell/blog/blog/2013/01/01/refinement-types-101.lhs/
>>>>> <http://goto.ucsd.edu/%7Erjhala/liquid/haskell/blog/blog/2013/01/01/refinement-types-101.lhs/>
>>>>>> <http://goto.ucsd.edu/%7Erjhala/liquid/haskell/blog/blog/2013/01/01/refinement-types-101.lhs/>
>>>>>> [2]: http://goto.ucsd.edu/~nvazou/refinement_types_for_haskell.pdf
>>>>> <http://goto.ucsd.edu/%7Envazou/refinement_types_for_haskell.pdf>
>>>>>> <http://goto.ucsd.edu/%7Envazou/refinement_types_for_haskell.pdf>
>>>>>>
>>>>>>
>>>>>>> On 11 May 2016, at 20:00, Adrian Zubarev via swift-evolution
>>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> <mailto:swift-evolution at swift.org>> wrote:
>>>>>>>
>>>>>>> Okay I’m fine with that for now. If you’d have to decide on some syntax
>>>>>>> for such a future, how would it look like? I’m just curious.
>>>>>>>
>>>>>>> I tend to square brackets Double[0.0 … 1.0], because otherwise it might
>>>>>>> look like a generic type, but I’m not sure if this type refinement could
>>>>>>> be applied to other types as well so we actually would stick to the
>>>>>>> generic type syntax here Float<-1.0 … 1.0>.
>>>>>>>
>>>>>>> --
>>>>>>> Adrian Zubarev
>>>>>>> Sent with Airmail
>>>>>>>
>>>>>>> Am 11. Mai 2016 bei 19:54:09, Matthew Johnson (matthew at anandabits.com <mailto:matthew at anandabits.com>
>>>>>>> <mailto:matthew at anandabits.com>) schrieb:
>>>>>>>
>>>>>>>> This is called a refinement type. It would be cool to explore that
>>>>>>>> direction in the future but it is definitely well out of scope for Swift 3.
>>>>>>>>
>>>>>>>> Sent from my iPad
>>>>>>>>
>>>>>>>> On May 11, 2016, at 12:45 PM, Adrian Zubarev via swift-evolution
>>>>>>>> <swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> <mailto:swift-evolution at swift.org>> wrote:
>>>>>>>>
>>>>>>>>> Hello Swift community. I'd like to discuss with you if we need
>>>>>>>>> something like this in Swift 3 or any future Swift version.
>>>>>>>>>
>>>>>>>>> As you may know there is no way to constrain a numeric type expect for
>>>>>>>>> some scope internal assertion or precodintions which may produce a
>>>>>>>>> runtime error if the input value is out of the defined bound.
>>>>>>>>>
>>>>>>>>> func foo(value: Int) {
>>>>>>>>> assert(value > 0 && value <= 10)
>>>>>>>>>
>>>>>>>>> // passed
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> How would it be if Swift would allow us to constraint numeric typs with
>>>>>>>>> ranges/intervals?
>>>>>>>>>
>>>>>>>>> func newFoo(value: Int<1...10>) {
>>>>>>>>> // no need for an assertion any more
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> We could go even further and add more then one range/interval:
>>>>>>>>>
>>>>>>>>> func someFoo(value: Int<0...20, 40...60>) { /* do some work */ }
>>>>>>>>>
>>>>>>>>> Not only integers should have this ability but also floating point
>>>>>>>>> types like Double and Float.
>>>>>>>>>
>>>>>>>>> Alternative form might look like this:
>>>>>>>>>
>>>>>>>>> Double[1.0...10.0]
>>>>>>>>> Float[0.0...1.0, 10.0...100.0]
>>>>>>>>>
>>>>>>>>> One downside of half opened ranges/intervals is the left side of its
>>>>>>>>> set. How do we exclude the left element?
>>>>>>>>>
>>>>>>>>> 1...10 means 1..<11 equals [1, 11)
>>>>>>>>>
>>>>>>>>> But how can we create something like (0.0, 1.0), do we need a strange
>>>>>>>>> looking binary operator 0.0>..<1.0?
>>>>>>>>>
>>>>>>>>> What do you think? I'd love to hear any feedback to this.
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Adrian Zubarev
>>>>>>>>> Sent with Airmail
>>>>>>>>> _______________________________________________
>>>>>>>>> swift-evolution mailing list
>>>>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> <mailto:swift-evolution at swift.org>
>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> <mailto:swift-evolution at swift.org>
>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>
>>>
>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>


More information about the swift-evolution mailing list