I have a type XY that has various fields and methods (a few dozen).
type XY struct {
Name string
SomeValue int
...
}
func (xy *XY) Do1() { ... }
func (xy *XY) Do2() { ... }
func (xy *XY) Do3() { ... }
...
Now I want to define a second type that embeds XY, keeping all fields and methods. But I do want to modify a few functions.
type AB struct {
XY
}
func (ab *AB) Do2() { ... }
So far so good. Now I want to pass AB to a function that takes XY.
func SomeFunc(xy *XY) { ... }
And here's where I stumble, no polymorphism.
I can pass *AB.XY to the function, but that wouldn't make use of AB's Do2 function anymore. I could make an interface for it, which is probably the intended way, but if SomeFunc were to need near to all functions of XY, say getters of almost all fields, I'd basically need to create a copy of XY, as an interface (possible use case: I'm on a server and have to send values to a client in a specific way). I wouldn't want to only make it an interface, because I'd have to redefine all fields and functions in all types that are using the interface.
I can think of solutions for this problem, e.g. making Do2 a closure, that is set depending on the "host" type, or an enum field in XY and changing the behavior of Do2 based on that "type" variable, or using reflection and interface{} in SomeFunc, but I'd like to know what the "correct" way in Go would be. How do you do this in the most efficient way, even if you have a lot of functions?
The correct way to do it in Go is to use interfaces. Create an interface of Do1, Do2, etc. and make SomeFunc work with the interface type.
Like #Ainar-G said, using an interface is the proper way for that kind of behavior, for example:
type Doer interface {
Do1()
Do2()
}
func (*S1) Do1() {
println("S1.Do1")
}
func (*S1) Do2() {
println("S1.Do2")
}
type S2 struct{ S1 }
func (*S2) Do1() {
println("S2.Do1")
}
func DoIt(d Doer) {
d.Do1()
d.Do2()
// you can use a type switch for specific corner cases, or implement a MarshalJson (or similar) interface for you types)
switch v := d.(type) {
case *S1:
println("Special case for S1", v)
case *S2:
println("Special case for S2", v)
}
}
playground
Related
I have code that follows the general design of:
protocol DispatchType {}
class DispatchType1: DispatchType {}
class DispatchType2: DispatchType {}
func doBar<D:DispatchType>(value:D) {
print("general function called")
}
func doBar(value:DispatchType1) {
print("DispatchType1 called")
}
func doBar(value:DispatchType2) {
print("DispatchType2 called")
}
where in reality DispatchType is actually a backend storage. The doBarfunctions are optimized methods that depend on the correct storage type. Everything works fine if I do:
let d1 = DispatchType1()
let d2 = DispatchType2()
doBar(value: d1) // "DispatchType1 called"
doBar(value: d2) // "DispatchType2 called"
However, if I make a function that calls doBar:
func test<D:DispatchType>(value:D) {
doBar(value: value)
}
and I try a similar calling pattern, I get:
test(value: d1) // "general function called"
test(value: d2) // "general function called"
This seems like something that Swift should be able to handle since it should be able to determine at compile time the type constraints. Just as a quick test, I also tried writing doBar as:
func doBar<D:DispatchType>(value:D) where D:DispatchType1 {
print("DispatchType1 called")
}
func doBar<D:DispatchType>(value:D) where D:DispatchType2 {
print("DispatchType2 called")
}
but get the same results.
Any ideas if this is correct Swift behavior, and if so, a good way to get around this behavior?
Edit 1: Example of why I was trying to avoid using protocols. Suppose I have the code (greatly simplified from my actual code):
protocol Storage {
// ...
}
class Tensor<S:Storage> {
// ...
}
For the Tensor class I have a base set of operations that can be performed on the Tensors. However, the operations themselves will change their behavior based on the storage. Currently I accomplish this with:
func dot<S:Storage>(_ lhs:Tensor<S>, _ rhs:Tensor<S>) -> Tensor<S> { ... }
While I can put these in the Tensor class and use extensions:
extension Tensor where S:CBlasStorage {
func dot(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
this has a few side effects which I don't like:
I think dot(lhs, rhs) is preferable to lhs.dot(rhs). Convenience functions can be written to get around this, but that will create a huge explosion of code.
This will cause the Tensor class to become monolithic. I really prefer having it contain the minimal amount of code necessary and expand its functionality by auxiliary functions.
Related to (2), this means that anyone who wants to add new functionality will have to touch the base class, which I consider bad design.
Edit 2: One alternative is that things work expected if you use constraints for everything:
func test<D:DispatchType>(value:D) where D:DispatchType1 {
doBar(value: value)
}
func test<D:DispatchType>(value:D) where D:DispatchType2 {
doBar(value: value)
}
will cause the correct doBar to be called. This also isn't ideal, as it will cause a lot of extra code to be written, but at least lets me keep my current design.
Edit 3: I came across documentation showing the use of static keyword with generics. This helps at least with point (1):
class Tensor<S:Storage> {
// ...
static func cos(_ tensor:Tensor<S>) -> Tensor<S> {
// ...
}
}
allows you to write:
let result = Tensor.cos(value)
and it supports operator overloading:
let result = value1 + value2
it does have the added verbosity of required Tensor. This can made a little better with:
typealias T<S:Storage> = Tensor<S>
This is indeed correct behaviour as overload resolution takes place at compile time (it would be a pretty expensive operation to take place at runtime). Therefore from within test(value:), the only thing the compiler knows about value is that it's of some type that conforms to DispatchType – thus the only overload it can dispatch to is func doBar<D : DispatchType>(value: D).
Things would be different if generic functions were always specialised by the compiler, because then a specialised implementation of test(value:) would know the concrete type of value and thus be able to pick the appropriate overload. However, specialisation of generic functions is currently only an optimisation (as without inlining, it can add significant bloat to your code), so this doesn't change the observed behaviour.
One solution in order to allow for polymorphism is to leverage the protocol witness table (see this great WWDC talk on them) by adding doBar() as a protocol requirement, and implementing the specialised implementations of it in the respective classes that conform to the protocol, with the general implementation being a part of the protocol extension.
This will allow for the dynamic dispatch of doBar(), thus allowing it to be called from test(value:) and having the correct implementation called.
protocol DispatchType {
func doBar()
}
extension DispatchType {
func doBar() {
print("general function called")
}
}
class DispatchType1: DispatchType {
func doBar() {
print("DispatchType1 called")
}
}
class DispatchType2: DispatchType {
func doBar() {
print("DispatchType2 called")
}
}
func test<D : DispatchType>(value: D) {
value.doBar()
}
let d1 = DispatchType1()
let d2 = DispatchType2()
test(value: d1) // "DispatchType1 called"
test(value: d2) // "DispatchType2 called"
In java you can declare an interface like this
public interface Foo<T>
{
public void doFoo(T result);
}
And you can use this as a type parameter in another method like this
public void doSomeAsyncTask(final Foo<MyObject> foo)
{
Runnable asyncRunnable = new Runnable()
{
#Override
void run()
{
MyObject result;
// do task to get result
foo.doFoo(result);
}
};
Thread asyncThread = new Thread(asyncRunnable);
asyncThread.start();
}
foo.doFoo(result);
}
As you can see I used the interface for callback from some asynchronous task that runs on a different thread.
UPDATE
Following this guide, I have come up with a solution similar to this
public protocol GenericProtocol {
associatedType T
func magic(result:T)
}
class GenericProtocolThunk<T> : GenericProtocol {
private let _magic : (T)
init<P : GenericProtocol where P.T == T>(_dep : P) {
_magic = p.magic
}
func magic(result: T) {
_magic(result)
}
}
Now in my doSomeAsyncTask method I can just pass GenericProtocolThunk<MyObject> as the parameter type. Is this the right way to achieve what I asked in the question? Honestly it looks quite ugly to me.
I think your problem boils indeed down to what is also noted in the blog post you link to:
"Protocols in Swift can be generic via abstract type members rather
than parameterisation. Consequently, the protocol itself can no longer
be used as a type but only as a generic constraint."
The (ugly) thunk based workaround looks like it solves your problem indeed, although to verify it would help if in your question you used similar terminology for both your Java and Swift examples, and they would be complete, including the type that actually contains the doSomeAsyncTask method to avoid possible confusions.
I can think of a few alternative more Swift friendly solutions if you can change the formulation a bit.
If you could describe Result too with a protocol, then the language isn't fighting against you quite so much. Compared to Java, conforming to a protocol (= implementing an interface) is also not limited to just class types, as shown in the below example so arguably you get a bit more rather out of the language to this end, than in Java:
import Foundation
protocol Result {
// any restrictions on Result that you need.
}
class A:Result { }
struct B:Result { }
enum C:Result { case X }
protocol Foo {
func doFoo(result:Result) -> Void
}
class Bar {
func doSomeAsyncTask(foo:Foo) -> Void {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
foo.doFoo(A())
foo.doFoo(B())
foo.doFoo(C.X)
}
}
}
Another alternative that I've used only recently myself in a related sort of problem is to model result as an enum which enumerates the possible result types, like below (incidentally, each of BibliographyItem, InlineMathFragment, Equation, BlockElement, InlineElement in my code example below are themselves protocols, not concrete types):
public enum Result {
case None
case BibliographyItems([BibliographyItem])
case InlineMathFragments([InlineMathFragment])
case Equations([Equation])
case BlockElements([BlockElement])
case InlineElements([InlineElement])
}
This is handy in a situation where your results come from some already known set of result types, and you commonly end up needing to deal with them in some conditional form.
You may want to simplify it to:
func doSomeAsyncTask<T>(callback: (T)->Void)
Check out this great video:
Rob Napier: Beyond Crusty: Real world protocols
The Swift developers seem to be saying that polymorphism should be accomplished via protocols, not class inheritance. For example, let's say you have an array of Shapes and the Shapes have different draw methods, Shape should be a protocol not a superclass.
protocol Shape {
func draw()
}
class Circle: Shape {
func draw() { print("Drawing a circle") }
}
class Triangle: Shape {
func draw() { print("Drawing a triangle") }
}
var shapes = [Shape]()
func fillShapes() {
//... Add circles and triangles to shapes ...
}
// run
fillShapes()
for shape in shapes {
shape.draw()
}
Now say you want to build Shapes based on user input which produces Strings. How would you write a Shape constructor that accepts String as input, in the most Swift-y way?
Cristik in this question suggests a global function like this:
func buildShape(kind: String) -> Shape? {
switch kind {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil // Error - bad Shape
}
}
This seems messy to me. I would rather the constructor was incorporated into Shape.
So my first attempt was
extension Shape {
static func build(kind: String) -> Shape? {
switch kind {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil // Error - bad Shape
}
}
}
But calling Shape.build("Circle")! produces error: static member 'build' cannot be used on instance of type 'Shape.Protocol'
I also tried
extension Shape {
class Factory {
func build(string: String) -> Shape? {
switch kind {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil
}
}
}
static let factory = Factory()
}
shapes.append(Shape.factory.build("Circle")!)
But it says Factory cannot be defined inside a protocol extension.
How does Swift want us to make flexible constructors?
You are overthinking the problem. There is nothing cleaner than a "global" function.
The problem with global functions in some languages is that they are polluting the global namespace which leads to name conflicts.
However, every Swift project has its own namespace and every framework it imports has also its own namespace, so there is no problem with name conflicts, thus, there is nothing wrong with global functions.
There is no need to wrap simple functions into Factory classes just to create an illusion of a namespace (this would be the correct solution in Java because you cannot create a global function in Java).
Function accessed as Shape.Factory.build(...) is not any better than a function accessed using buildShape(...).
If you really want to have a namespace, you can just wrap your functions into a struct:
struct Shapes {
static func buildShape(kind: String) -> Shape? {
switch kind {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil // Error - bad Shape
}
}
}
and call it as Shapes.buildShape(...) but there is not real need for it.
The protocol cannot (and in my personal opinion, should not) be used as a "factory".
A protocol is a set of rules that a construct follows, not a concrete construct itself. A factory should be a concrete type, not a "set of rules". The solution is to have a separate ShapeFactory construct (be it a class, struct or enum), with static/non-static build functions.
As for the "messy" part; I agree. It is kind of messy. Swift doesn't isn't capable of things like struct Shape.Factory { }. There's no real way to get around it without making a compromise / rewriting the compiler, the latter of which can actually be achieved with some good constructive criticism at the swift-evolution mailing list.
I wouldn't do for a Factory method on Shape, neither a protocol nor a super class should know details about implementations or derived classes. I'd rather go for a ShapeBuilding protocol and a factory class.
protocol Shape {
func draw()
}
protocol ShapeBuilding {
static func build(kind:String) -> Shape?
}
struct ShapeBuilder: ShapeBuilding {
static func build(kind: String) -> Shape? {
switch kind {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil // Error - bad Shape
}
}
}
let circle = ShapeBuilder.build("Circle")
Motto: Just because Swift offers extensions we don't have to force everything into extension.
All three of you have given me good insight into this question. I now see that it is a much deeper question than I first imagined.
Here is my consolidated answer.
The Swift message is Avoid Building Abstract Class Hierarchy. Protocols are glue (or grease maybe?) not abstract superclasses.
In Swift, a protocol like Shape is not an abstract superclass of Circle and Triangle in the Java sense. Don't try to put factory constructors (constructors that can return more than one type) into protocols.
The previous version of this post suggested that shapes could hold the differentiated construction code. But I have changed my mind. shapes shouldn't know about circles and triangles either. shapes is polymorphic and that's what polymorphic means. Therefore I have substantially changed this post. If there was strike-through I would use it but I don't see it.
I now think a global function like this is the right way.
func buildShapeFrom(userInput: String) -> Shape? {
switch userInput {
case "Circle": return Circle()
case "Triangle": return Triangle()
default: return nil // Error - bad input
}
}
If there's an appropriate structure on the user input side, perhaps it could go there. The user cares whether it is a circle or a triangle, but Shape shouldn't and neither should shapes.
Comments welcome.
I have a few functions that are identical except for the fact that they handle two different types. I wish to keep my code more DRY so I would like to turn them into one function for two types. But how do I do that?
I know how to create a generic function: func doSomething<T>(arg: T) { ... }
I also know how to create a generic function that only accepts objects of a certain protocol:
func doSomething<T: Event>(arg: T) { ... }
Now I've solved this little problem before when I wanted a function that would accept both Strings and objects that conform to the Event protocol. In that case I solved it quite easily by just making String conform to the Event protocol like so: extension String: Event {}. (Event is an empty protocol anyway)
But this time the two types I'm dealing with are String and Event.Type. And in that case I can't use the same trick, because meta-types cannot be extended or be used to extend other types with.
Is there a way to write something like this?
func doSomething<T where T == Event.Type || T == String>(arg: T) { ... }
Edit, I'll explain more why I'm doing this:
I'm writing an event-dispatcher. Events can either be a string like "user.birthday" accompanied with a payload or an object that conforms to the Event protocol. I want to support both, because different developers have different preferences. So I can define events and listeners like so:
struct UserWonAward: Event {
let user: User
}
events.listenTo("user.birthday") {
(user: User) in
print("Happy birthday \(user.name)!")
}
events.listenTo {
(event: UserWonAward) in
print("Congratulations \(event.user.name)!")
}
And now here comes the thing I want help with. Sometimes I'll line up a few events in a queue and then later flush the queue of a specific type, like so:
let user1 = User(name: "John Doe")
let user2 = User(name: "Jane Doe")
events.queue("user.birthday", payload: user1)
events.queue("user.birthday", payload: user2)
events.queue(UserWonAward(user: user1))
events.queue(UserWonAward(user: user2))
// Some time later
events.flushQueueOf("user.birthday")
events.flushQueueOf(UserWonAward)
As you can see, in that flushQueueOf() method I can input either a String or an Event.Type. Right now I have written two separate methods for that, but the code in those two methods are nearly identical so I really want to merge them into one method.
No.
You can have type intersections - ie "and" logic (where the type is bound by multiple types), but you can't have a union - ie "or" logic like you want.
If you think about it, it doesn't make sense, especially with java's type safety.
If your method works with either of two types, and you want to follow DRY:
public void method(TypeA x) {
methodAnyType(x);
}
public void method(TypeB x) {
methodAnyType(x);
}
private void methodAnyType(Object x) {
// x is either TypeA or TypeB
}
This question already has answers here:
What is the benefit of nesting functions (in general/in Swift)
(3 answers)
Closed 6 years ago.
What is the practical use of nested functions? It only makes the code harder to read and doesn't make a particular case easy.
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backwards ? stepBackward : stepForward
}
Source
I think the core of your question is: Why not use private function instead of an ugly nested function?
Simply put, nested functions can ease readability and encapsulation.
Similarly one can ask, what's the practical use of local variables (of a function) vs instance variables? To me it's really the same question. Only that nested functions are less common.
Readability
A private function can still be accessed from other functions in your class. The same isn't true for nested functions. You're telling your developers, this only belongs to this function (contrary to private functions where they belong to the entire class). Back off and don't mess with it, if you need similar capability, go write your own!
The moment you see a private function you have to think, which function will call it. Is it the first function or the last? Let me search for it. Yet with a nested function you don't have to look up and down. It's already known which function will call it.
Also if you have 5 private functions, where 3 of them are called in a single public function then by nesting them all under the same public function you're communicating to other developers that these private functions are related.
In short, just as you don't want to pollute your public namespace, you don't want to pollute your private namespace.
Encapsulation
Another convenience is that it can access all the local parameters to its parent function. You no longer need to pass them around. This would eventually mean one less function to test, because you've wrapped one function inside another. Additionally if you're calling that function in a block of the non-nested function, then you don't have to wrap it into self or think about creating leaks. It's because the lifecycle of the nested function is tied to the lifecycle of its containing function.
Another use case would be when you have very similar functions in your class, say like you have:
extractAllHebrewNames() // right to left language
extractAllAmericanNames() // left to right language
extractAllJapaneseNames() // top to bottom language
Now if you have a private func named printName (that prints names), it would work if you switch the case based on language, but what if just you don't/can't do that. Instead you can write your own nested functions (They could all now have the exact same name. because each is in a different namespace.) inside each separate extract function and print the names.
Your question is somewhat similar, to why not use 'if else' instead of a 'Switch case.
I think it's just a convenience provided (for something that can be dealt without using nested functions).
NOTE: A nested function should be written before it's callsite within the function.
Error: use of local variable 'nested' before its declaration
func doSomething(){
nested()
func nested(){
}
}
No Error:
func doSomething(){
func nested(){
}
nested()
}
Similarly a local variable used in a nested function must be declared before the nested function
BE AWARE:
If you're using nested functions, then the compiler won't enforce self checks.
The compiler is not smart enough. It will NOT throw error of:
Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit
This could result in hard to find memory leaks. e.g.
class P {
var name: String
init(name: String) {
print("p was allocated")
self.name = name
}
func weaklyNested() {
weak var _self = self
func doX() {
print("nested:", _self?.name as Any)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
doX()
}
}
func stronglyNested() {
func doZ() {
print("nested:", name)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
doZ() // will NOT throw error of: `Call to method 'doZ' in closure requires explicit 'self.' to make capture semantics explicit`
}
}
deinit {
print("class P was deinitialized")
}
}
class H {
var p: P
init(p: P) {
self.p = p
}
}
var h1: H? = H(p: P(name: "john"))
h1?.p.weaklyNested()
h1 = nil // will deallocate immediately, then print nil after 2 seconds
var h2: H? = H(p: P(name: "john"))
h2?.p.stronglyNested()
h2 = nil // will NOT deallocate immediately, will print "john" after 2 seconds, then deallocates
tl;dr solution:
use weak var _self = self and inside the nested function reference to self with the weak reference.
don't use nested functions at all :( Or don't use instance variables inside your nested functions.
This part was written thanks to this original post from Is self captured within a nested function?
One use case is operations on recursive data structures.
Consider, for instance, this code for searching in binary search trees:
func get(_ key: Key) -> Value? {
func recursiveGet(cur: Node) -> Value? {
if cur.key == key {
return cur.val
} else if key < cur.key {
return cur.left != nil ? recursiveGet(cur: cur.left!) : nil
} else {
return cur.right != nil ? recursiveGet(cur: cur.right!) : nil
}
}
if let root = self.root {
return recursiveGet(cur: root)
} else {
return nil
}
}
Of course, you can transform the recursion into a loop, doing away with the nested function. I find recursive code often clearer than iterative variants, though. (Trade off vs. runtime cost!)
You could also define recursiveGet as (private) member outside of get but that would be bad design (unless recursiveGet is used in multiple methods).
There is the principle (since Objective-C) that "code can be data". You can pass code around, store it in a variable, combine it with other code. This is an extremely powerful tool. Frankly, if I didn't have the ability to treat code as data, most of the code I write would be ten times harder to write, and ten times harder to read.
Functions in Swift are just closures, so nested functions make perfectly sense, since this is how you write a closure when you don't want to use one of the many available shortcuts.
In your example, you can create a variable which is also a function like this:
var myStepFunction = chooseStepFunction(true)
myStepFunction(4)
The benefit of nested function is really nice. For example, let's say you are building an app for the calculator, you can have all your logic in one function, as the following:
func doOperation(operation: String) -> ((Double, Double) -> Double)? {
func plus(s: Double, d: Double) -> Double {
return s + d
}
func min(s: Double, d: Double) -> Double{
return s - d
}
switch operation {
case "+":
return plus
case "-" :
return min
default :
return nil
}
}
var myOperationFunction = doOperation("-")?(4, 4) // 0
var myOperationFunction2 = doOperation("+")?(4, 5) //9
In some cases, you are not allowed to see the implementation of some function, or not responsible for them. Then hidding them inside other function is really a good approach. For instance, assume that you colleague is reaponsible for developing the plus and min functions, he/she will do that, and you just use the outer function.
It is deferent from closure, because in clouser, you pass your logic to other logic, which will call yours. It is kind of plugin. For instance, after calling the http request, you can pass the code that you want your app to do when receiving the response from the server