[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:18:03 CDT 2016


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
>


More information about the swift-evolution mailing list