Swift: Could we add operator to Python Interoperability

Created on 14 Apr 2019  路  3Comments  路  Source: tensorflow/swift

If we want to use the == operator to filter np array,

   idxs = np.flatnonzero(y_train == y)

we can do it in Swift,

    var idxs = np.flatnonzero(y_train == y)

with the redefinition of equal operator

let op = Python.import("operator")
public func == (lhs: PythonConvertible, rhs: PythonConvertible) -> PythonObject {
    return op.eq(lhs, rhs)
}

Most helpful comment

We already have == with the normal Bool result:

public static func == (lhs: PythonObject, rhs: PythonObject) -> Bool {
return lhs.compared(to: rhs, byOp: Py_EQ)
}

Swift does support overloading on return type, but you almost never want it. I'd recommend using a different operator for this, just use op.eq directly:

var idxs = np.flatnonzero(op.eq(y_train, y))

or use a conversion to PythonObject:

var idxs = np.flatnonzero(PythonObject(y_train == y))

All 3 comments

We already have == with the normal Bool result:

public static func == (lhs: PythonObject, rhs: PythonObject) -> Bool {
return lhs.compared(to: rhs, byOp: Py_EQ)
}

Swift does support overloading on return type, but you almost never want it. I'd recommend using a different operator for this, just use op.eq directly:

var idxs = np.flatnonzero(op.eq(y_train, y))

or use a conversion to PythonObject:

var idxs = np.flatnonzero(PythonObject(y_train == y))

@lattner Thanks for your reply! It is my honor to discuss the Python Interoperability of the Swift!

Another proposal is ExpressByTupleLiteral. It is mentioned several times in the Swift Evolution forum.
I found it is pretty needed for the Python Interoperability.
For example, the reshape function:

X_train = ... # some np array result
X_train = X_train.reshape((X_train.shape[0], -1))

Currently, we must define some function or using the PythonObject.init(tupleOf:...) or Python.tuple([...]) to map the tuple values to the Python tuple. There is no direct way to map Swift tuple to Python tuple.

var X_train: PythonObject = ... // some np array result

// option1
X_train = X_train.reshape(Python.tuple([X_train.shape[0], -1]))

// option2
X_train = X_train.reshape(PythonObject(tupleOf: X_train.shape[0], -1))

// option3
X_train = X_train.reshape(t(X_train.shape[0], -1)) // define a shortcut function `t`
public func t(_ vals: PythonConvertible...) -> PythonObject {
    return PythonObject(tupleContentsOf: vals)
}

If there is an ExpressByTupleLiteral feature then it is very easy to map Swift tuple to Python tuple:

var X_train: PythonObject = ... // some np array result

// option4
X_train = X_train.reshape((X_train.shape[0], -1))

// with the defination by adding ExpressibleByTupleLiteral protocol
extension PythonObject : ExpressibleByTupleLiteral {
    public init<T: PythonConvertible>(tupleLiteral elements: PythonConvertible...) {
        self.init(tupleOf: vals)
    }
}

Definitely, I've love to see an ExpressibleByTupleLiteral feature. Unfortunately, I suspect that that is blocked by the lack of variadic generics - it isn't important for the Python usecase, but the tuple should be allowed to have different element types in general.

Was this page helpful?
0 / 5 - 0 ratings