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

Vladimir.S svabox at gmail.com
Wed May 18 07:12:52 CDT 2016


 > 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/>
> [2]: http://goto.ucsd.edu/~nvazou/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>> 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>) 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>> 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>
>>>> 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
>


More information about the swift-evolution mailing list