> 
> I believe that adding explicit syntax would be counterproductive to your 
> goals, and would not make dynamic lookup syntax more clear.  I assume that 
> you would also want the same thing for DynamicCallable too, and operator 
> overloads, subscripts, and every other operation you perform on these values, 
> since they all have the exact same behavior.
> 
> If we required some syntax even as minimal as “foo.^bar” and "baz^(42)”, that 
> change would turn this (which uses runtime failing or IUO return values like 
> AnyObject):
> 
>       let np = Python.import("numpy")
>       let x = np.array([6, 7, 8])
>       let y =  np.arange(24).reshape(2, 3, 4)
>       
>       let a = np.ones(3, dtype: np.int32)
>       let b = np.linspace(0, pi, 3)
>       let c = a+b
>       let d = np.exp(c)
>       print(d)
> 
> into:
> 
>       let np = Python.import("numpy")
>       let b = np^.array^([6, 7, 8])
>       let y =  np^.arange^(24)^.reshape^(2, 3, 4)
>       
>       let a = np^.ones^(3, dtype: np^.int32)
>       let b = np^.linspace^(0, pi, 3)
>       let c = a+^b
>       let d = np^.exp^(c)
> 
> This does not improve clarity of code, it merely serves to obfuscate logic.  
> It is immediately apparent from the APIs being used, the API style, and the 
> static types (in Xcode or through static declarations) that this is all 
> Python stuff.  When you start mixing in use of native Swift types like 
> dictionaries (something we want to encourage because they are typed!) you end 
> up with an inconsistent mismash where people would just try adding syntax or 
> applying fixits continuously until the code builds.

That’s not Swift. You just wrote a bunch of Python. For example, Swift has a 
native Int32.+ operator which fails on overflow - does your example also do 
that? Anybody’s guess! Does your numpy array conform to Collection? I guess 
not, because it’s an opaque Python value.

That’s exactly the kind of stuff I, as a user of the language, really don't 
want to see mixed together with real Swift. I appreciate the need to use 
functionality from libraries written in Python, but I don’t appreciate it being 
so invisible and pervasive throughout the language. If you have a bunch of 
Python logic, I’d prefer you wrote as much of it as possible in Python, with as 
few bridging points to Swift as you can get away with. I remain convinced that 
this design encourages the opposite - because, as you said earlier, it’s “too 
good”.

As for the point about Swift already including non-marked, potentially-crashing 
operations (like the + operator, or Array subscripting): nobody likes that 
behaviour! Whenever I come to a new Swift codebase, I almost universally find 
that people have written their own “safe” Array accessor which integrates 
bounds-checking and returns an Optional. The issue has come up here many, many 
times for inclusion in the standard library. I certainly would not use it as 
justification for adding more of those kinds of unmarked, potentially-unsafe 
operations. Also, enough Swift developers know about the Array subscript 
behaviour that the square brackets almost become a marker, like “!”, of a 
potentially-failing operation. The same is not true of the dot operator, in 
general.

I also don’t agree with the comparisons to Objective-C/AnyObject dispatch. It’s 
true that it’s unsafe to an extent, but it’s also orders of magnitude safer 
than this sort of dispatch. Clang is integrated in to the compiler, and can at 
least perform some rudimentary checking of method signatures/selectors. This 
sort of dispatch provides absolutely no protections whatsoever — is “arange” 
really a function? Is it not really a typo for “arrange”? That’s something I 
need to Google. With regular Swift I can assume that if the compiler allows it, 
there is a function called “arange” somewhere, and all I need to worry about is 
whether the erased AnyObject is of the correct type to respond to that message. 
And as I said earlier, AnyObject is incredibly rare in practice anyway. So no, 
I don’t agree that we should just keep lowering the safeguards; it’s like 
demolishing your house because of one draughty door.

What I could support, would be some kind of optional syntax, possibly with some 
kind of associated scope which allows you omit it. Something like:

// Normally, optionals are required.
let result: PythonObject? = pythonObj.someProperty?.someFunction(1, 2, 3)

// Within a special scope, you can omit them. The scope will bail at the first 
lookup failure and return nil.
let result: PythonObject? = Python {
    return pythonObj.someProperty.someFunction(1, 2, 3)
}

Perhaps the “Python” object could conform to a protocol with an associated type 
for the objects it can implicitly unwrap. There would be some additional 
compiler work, for sure, but that’s secondary to a good language model IMO 
(easy for me to say, I know).


- Karl
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to