I would argue that doesn't really matter, because it's the humans who can't differentiate it. I'd posit that most people weren't aware that NSObject
is both a protocol and a class. It's confusing.
A thousand times yes!
I'd like to see Result
and Optional
rationalised. It keeps coming up and everyone and their dog has a different solution. Even me: Introducing an “Unwrap or Throw” operator - #26 by jjrscott
I do like @tera's idea, but I'm not sure how I feel about more dots:
I think a warning should suffice. We don’t need to change all the semantics of protocol conformances. Of course, suppressing that error may be hard to do elegantly, but I think this is a more viable solution.
Again, I think requiring this marker may be too aggressive but I’m definitely in favor of adding such a feature. Maybe autocomplete could add this marker automatically, but even adding it to default implementations in protocol extensions would be incredibly useful.
I'd love to see Optional
removed in favor of Result with a MissingValueError
(With all conveniences and syntax sugar intact.
Something that I just remembered:
- I'd love the "everything can be an
AnyObject
" trap to be gone on Darwin platforms at least from the Swift perspective, I personally don't mind whatever Objective-C can do.
So far I'm happy to see more community members to join and share their personal opinions and differences for the language they would like to see.
Some things I agree with, some other things I personally strongly disagree. However this isn't the thread to publicly disagree with other opinions, not even if some of them do sound very extreme. It is the exact opposite, everyone should accept ANY opinion (as long as those are not intentionally meant as a joke).
Keep going!
There are bunch of great and intriguing ideas in the thread so far! Here's some from my wishlist...
- Closed protocols (ie, protocols that are public but cannot be adopted by anyone). There are times when I want to express that some types are all related, but I intentionally do no support anyone else making a related type.
CKRecordValueProtocol
is one such protocol that would benefit from this, IMO. -
public import
,internal import
, andprivate import
. - Overhaul access control stuff so I can finally do things like
typeprivate
,public-and-open-but-only-for-subtypes
,friend
, etc - Death to
fileprivate
- also:
module CustomModule { ... }
- add the
!!
and?!
operators (ie "crash if nil" and "throw if nil", respectively). These are ridiculously helpful when doing custom decoding logic:init(from anyJSON: Any) { // before: guard let json = anyJSON as? [String: Any] else { fatalError("Getting anything except a dictionary is a logic bug") // yes, I can use `as!` here, but if I have a way to give a custom error message, // I'd like to provide one } guard let value = json["key"] as? String else { throw SomeJSONError... } self.value = value // after: let json = anyJSON as? [String: Any] !! "Getting anything except a dictionary is a logic bug" self.value = try (json["key"] as? String) ?! SomeJSONError... }
- complete interoperation between
throws
methods and result methods. Example:
... perhaps for// given func myThrowingFunction() throws -> Foo { ... } // this should be callable as either: let result = myThrowingFunction() // "result" is a Result<Foo, Error> // or (currently) let foo = try myThrowingFunction() // "foo" is a Foo
async
methods as well, although I haven't thought about that as much. - typed
throws
- a lot more synthesis around enums (
isCase: Bool
andvar casePayload: PayloadType?
accessors) - deprecate and replace
Codable
+1000. the current Codable
design is fine for infrequently-called functionality, but the performance is just terrible for high-throughput use cases.
There are a lot of ideas in this thread that I both agree and disagree with, but this has been one of my #1 feature requests for a long time.
I wish try
was applied after performing functions on Result
so method chaining could express behavior like:
let value = try doFoo()
.logError(logger) { "Failed to do bar: \($0)" }
let value = try doFoo()
.replaceError(fallbackValue)
In a similar vein, I wish try
was expressible in a library so similar control flow keywords could be rewritten for Optional
and Bool
. ex:
unwrap returnsOptional() // returns nil from the calling function if returnsOptional returns nil
require returnsBool() // returns false from the calling function if returnsBool returns false
This could enable code like:
require throwingFn()
.logError ...
.isSuccess
from me.
It's a bit less succinct as in your example but we can do this already:
let fromThrowingToResult = Result { try foo() }
let fromResultToThrowing = try! bar().get()
func foo() throws -> Int {
if (x & 1) == 0 {
throw NSError(domain: "", code: -1, userInfo: nil)
} else {
return x + 1
}
}
func bar() -> Result<Double, Error> {
if y < 0 {
return .failure(NSError(domain: "", code: -1, userInfo: nil))
} else {
return .success(sqrt(y))
}
}
Do you think it can be optimised in the current form without complete rehaul / deprecation / replacing, or is there some inherent drawback deep in its design that makes it slow?
Note, that if you write it on a single line it becomes:
try doFoo().logError()
try doFoo().replaceError()
which shows the need for parens:
(try doFoo()).replaceError()
With trailing syntax for throw chaining could have been more natural:
doFoo().try.replaceError()
and I'd put try
after each throwing function (similar to how we can put more than one !
or ?
):
_ = foo?.bar?.baz
_ = quz.try.quux.try
ditto for await.
var allIWantForSwiftmas: Is? = nil
- changing
.filter
to.filtered
(could be backwards-compatible) - implicit returns
- if expressions (could be backwards-compatible)
- more expression-based syntax instead of statement-based syntax (could be backwards-compatible)
Quite a breaking change: denote the minimal integer value (for signed integers, so -128 for Int8, -32768 for Int16, etc), and the maximum integer value (for unsigned integer values) as an overflow marker, that would be propagated across integer ops and end up in the result. As an alternative for signs integers use one-complement representation and denote -0
value for overflow marker. The range of integers will become one value smaller which might be a show stopper for some algorithms but ok for (hopefully) most. overflow == overflow
and we can make an arbitrary ruling that overflow > any non overflown int
If that's done we can eventually deprecate trapping on int math overflows, or make it optional so developer can choose between the two behaviours (actually three as there's &+
and co).
I wish we could have fitted in the renaming of dropFirst
/ dropLast
, before the source stability bar was raised. The tense of the verb is wrong, and drop sounds so much more destructive than (for example) removingFirst()
.
Whilst we maybe technically could still do this change, with a long tail of deprecation, the third-party ecosystem of libraries have also now matched the stdlib names (like in Combine
). So it feels somewhat stuck in stone as a quirk of history at this point.
the protocol existential dispatch gets the most blame, but it also has to do with the way UnkeyedDecodingContainer
and friends track their codingPath
. every decoding operation pushes a debugging breadcrumb onto the stack, which is wasteful and only needed if decoding actually fails.
this is why swift-json
opted for a functional (instead of protocol-oriented) decoding interface, which only logs debugging traces if an error is thrown inside the decoder.
Minor aside
FWIW, this isn't quite true — codingPath
is exposed to also allow types to tell where they are in the encoding tree at a given point, and optionally apply different encoding rules if they need to. It's also helpful for debugging, but that's not the only use-case.
I'm actually surprised that codingPath
would be a performance pitfall for the APIs; as far as I remember, nothing in the APIs mandates that codingPath
be built eagerly, and it could very well get built lazily upon access.
(I think it's also important to try to separate the implementation of specific encoders and decoders from the API at large, but that's definitely not always easy, given the relatively small number of data points to work with.)
I would welcome breaking changes to:
- the ownership model for improved ergonomics and control over performance
- Codable, it's really quite cool, but it's time for something faster with fewer limitations
I would like to see AnyValue protocol in places where you wouldn't want a class to conform to protocol