NSAttributedString attributesAtIndex return an optional.


(James Lee) #1

Hi all,

Been playing around with NSAttributedString and cannot decide on the best way to implement the (attributesAtIndex: effectiveRange) and other methods with similar functionality.

In the ObjC world I would expect an empty NSDictionary even in cases where the location is greater than the length of the string.

In the swift world, I am of the leaning that the functions should return optionals and in the aforementioned scenario 'nil' would be returned.

Wanted to get other people's thoughts on this.


(Brent Royal-Gordon) #2

Been playing around with NSAttributedString and cannot decide on the best way to implement the (attributesAtIndex: effectiveRange) and other methods with similar functionality.

In the ObjC world I would expect an empty NSDictionary even in cases where the location is greater than the length of the string.

Personally, if I indexed past the end of an attributed string, I would expect a precondition to fail and (since Swift can't catch assertion failures) my app to crash. (And from what I can tell, the Apple Foundation versions of these APIs do not return an optional.)

(Sorry about the duplicate, James—didn’t hit Reply All when I should have.)

···

--
Brent Royal-Gordon
Architechies


(James Lee) #3

Personally, if I indexed past the end of an attributed string, I would expect a precondition to fail and (since Swift can't catch assertion failures) my app to crash. (And from what I can tell, the Apple Foundation versions of these APIs do not return an optional.)

--
Brent Royal-Gordon
Architechies

It is worth noting that the current OSX documentation does raise an NSRangeException in the case discussed above. With the throw capabilities in Swift 2 this makes sense.

As you have said, it seems a lot of Foundation API's do not return Optionals. I feel this a hangover from ObjC where an empty object (in this case an NSDictionary) would be returned. To me this is what Optionals are there to replace.


(Philippe Hausler) #4

NSException != throw in swift…
NSExceptions should be treated as assert, fatalError, or precondition (precondition in this case is probably preferred)

···

On Dec 8, 2015, at 7:31 AM, James Lee via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

Personally, if I indexed past the end of an attributed string, I would expect a precondition to fail and (since Swift can't catch assertion failures) my app to crash. (And from what I can tell, the Apple Foundation versions of these APIs do not return an optional.)

--
Brent Royal-Gordon
Architechies

It is worth noting that the current OSX documentation does raise an NSRangeException in the case discussed above. With the throw capabilities in Swift 2 this makes sense.

As you have said, it seems a lot of Foundation API's do not return Optionals. I feel this a hangover from ObjC where an empty object (in this case an NSDictionary) would be returned. To me this is what Optionals are there to replace.
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev


(Lily Ballard) #5

I agree that precondition is appropriate here. Swift has Optionals and
throws, yes, but Swift also uses preconditions to do things like range
checks on subscripting. I believe the general rule is that if something
is a programmer error, it should be a hard failure (i.e. a
precondition/assert/fatalError), and throws should only be used for
"soft" errors. So subscripting past the end of a collection is a
programmer error, but e.g. trying to decode a non-JSON string as JSON
with NSJSONSerialization is a "soft" error.

Also, as an aside, when an API returns a type that already has a notion
of an empty value (e.g. a Dictionary has [:]), then you should only wrap
it in an Optional if there's a specific reason to differentiate between
an empty value and no value at all. In the case of attributesAtIndex,
I'd expect it to return a non-optional Dictionary, because every valid
index does have a notion of attributes, even if the attribute set is
empty at that location. And passing an invalid index is a programmer
error and should use precondition.

-Kevin Ballard

···

On Tue, Dec 8, 2015, at 07:59 AM, Philippe Hausler via swift-corelibs-dev wrote:

NSException != throw in swift…
NSExceptions should be treated as assert, fatalError, or precondition
(precondition in this case is probably preferred)

> On Dec 8, 2015, at 7:31 AM, James Lee via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:
>
>
>>
>> Personally, if I indexed past the end of an attributed string, I would expect a precondition to fail and (since Swift can't catch assertion failures) my app to crash. (And from what I can tell, the Apple Foundation versions of these APIs do not return an optional.)
>>
>> --
>> Brent Royal-Gordon
>> Architechies
>>
>
> It is worth noting that the current OSX documentation does raise an NSRangeException in the case discussed above. With the throw capabilities in Swift 2 this makes sense.
>
> As you have said, it seems a lot of Foundation API's do not return Optionals. I feel this a hangover from ObjC where an empty object (in this case an NSDictionary) would be returned. To me this is what Optionals are there to replace.
> _______________________________________________
> swift-corelibs-dev mailing list
> swift-corelibs-dev@swift.org
> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

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


(Ross Kimes) #6

This may be better for the swift-evolution list, but I really do not like the fact that subscripting is a "hard" error. I think the language should have as little hard errors as possible to improve on how much the compiler can check for you. It seems like a holdover from C to me. Having those be crashing errors makes it difficult to scan for code that is handling errors poorly (you can't just look for try! or !). There is nothing that looks like it could be dangerous in subscripting.

I would much prefer these types of things throw errors. Since straight subscripting also seems like a last resort in other parts of the language, having an 'throws' version would encourage usage of APIs that don't involve straight subscripting.

So in this particular case I would prefer retuning a non-optional dictionary (because empty dictionaries are a valid set of attributes) and throw an error for going out of bounds.

(Sorry for the double email Kevin. Forgot to switch the recipient before replying.)

Ross

···

On Dec 8, 2015, at 2:05 PM, Kevin Ballard via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

I agree that precondition is appropriate here. Swift has Optionals and
throws, yes, but Swift also uses preconditions to do things like range
checks on subscripting. I believe the general rule is that if something
is a programmer error, it should be a hard failure (i.e. a
precondition/assert/fatalError), and throws should only be used for
"soft" errors. So subscripting past the end of a collection is a
programmer error, but e.g. trying to decode a non-JSON string as JSON
with NSJSONSerialization is a "soft" error.

Also, as an aside, when an API returns a type that already has a notion
of an empty value (e.g. a Dictionary has [:]), then you should only wrap
it in an Optional if there's a specific reason to differentiate between
an empty value and no value at all. In the case of attributesAtIndex,
I'd expect it to return a non-optional Dictionary, because every valid
index does have a notion of attributes, even if the attribute set is
empty at that location. And passing an invalid index is a programmer
error and should use precondition.

-Kevin Ballard

On Tue, Dec 8, 2015, at 07:59 AM, Philippe Hausler via > swift-corelibs-dev wrote:

NSException != throw in swift…
NSExceptions should be treated as assert, fatalError, or precondition
(precondition in this case is probably preferred)

On Dec 8, 2015, at 7:31 AM, James Lee via swift-corelibs-dev <swift-corelibs-dev@swift.org> wrote:

Personally, if I indexed past the end of an attributed string, I would expect a precondition to fail and (since Swift can't catch assertion failures) my app to crash. (And from what I can tell, the Apple Foundation versions of these APIs do not return an optional.)

--
Brent Royal-Gordon
Architechies

It is worth noting that the current OSX documentation does raise an NSRangeException in the case discussed above. With the throw capabilities in Swift 2 this makes sense.

As you have said, it seems a lot of Foundation API's do not return Optionals. I feel this a hangover from ObjC where an empty object (in this case an NSDictionary) would be returned. To me this is what Optionals are there to replace.
_______________________________________________
swift-corelibs-dev mailing list
swift-corelibs-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-corelibs-dev

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

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


(Brent Royal-Gordon) #7

This may be better for the swift-evolution list, but I really do not like the fact that subscripting is a "hard" error. I think the language should have as little hard errors as possible to improve on how much the compiler can check for you.

I think the idea is that, if you’re subscripting incorrectly, chances are you didn’t anticipate the possibility that your subscript might fail and probably didn’t write code that’s prepared to handle that error. If you did anticipate that possibility, you would have made sure there was a range check in the first place.

Ultimately, since Swift.org Foundation is meant to present the same interface as Apple Foundation, I don’t think we have much of a choice about this anyway. Apple Foundation’s version of this method is non-optional and non-throwing. If we deviate from that, we lose compatibility.

···

--
Brent Royal-Gordon
Architechies