Is there an equivalent of Ruby's instance_eval in Swift? - swift

In ruby I can pass a block into a method and have the block evaluated in the context of the receiving object.
class Receiver
def method_a
puts "hello from method_a"
end
def method_b
puts "hello from method_b"
end
def define_something &action
method_a
instance_eval &action
end
end
thing = Receiver.new
thing.define_something { method_b }
which produces the following output:
hello from method_a
hello from method_b
Whats the right way to implement something like this in Swift?
Here is what I have, but of course Xcode complains that methodB is an unresolved identifier.
class Receiver {
func methodA() {
print("hello from method A")
}
func methodB() {
print("hello from method B")
}
func defineSomething( action: () -> Void ) {
methodA()
action()
}
}
let thing = Receiver()
thing.defineSomething { methodB() }
BTW, this can also be done in Kotlin which has the idea of a function type with a receiver.
for example the following produces similar output to what the ruby example produces.
class Receiver {
fun methodA() = println("hello from methodA")
fun methodB() = println("hello from methodB")
fun defineSomething( action: Receiver.() -> Unit) {
methodA()
action()
}
}
fun main(args: Array<String>) {
val thing = Receiver()
thing.defineSomething { methodB() }
}
hello from methodA
hello from methodB

I don't know of a way to do that in the language. You can do it manually by having action take a Receiver instance as input, and then call action(self) inside of defineSomething(action:).
class Receiver {
func methodA() {
print("hello from method A")
}
func methodB() {
print("hello from method B")
}
func defineSomething(action: (_: Receiver) -> Void ) {
methodA()
action(self)
}
}
let thing = Receiver()
thing.defineSomething { $0.methodB() }
hello from method A
hello from method B

Related

Swift Compiler lose its polymorphical context

First, I'm new to Swift language and have worked using python which is 'dynamic typed' language, so don't know exact compiler's perspective.
Below code is a simple code snippet to practice what Apple said POP(protocol oriented programming).
Snippet contains various ReturnClasses, RunnerClasses(each has different return type) and actual runner which just run RunnerClasses. Also has Selector enum to pretend dynamic dispatch.
protocol Return {
var value: Int { get set }
init(_ value: Int)
}
final class Return0: Return {
var value: Int
init(_ value: Int) {
print("return 0")
self.value = value
}
}
final class Return1: Return {
var value: Int
init(_ value: Int) {
print("return 1")
self.value = value + 50
}
}
final class Return2: Return {
var value: Int
init(_ value: Int) {
print("return 2")
self.value = value + 500
}
}
protocol FirstProtocol {
init()
func a() -> Return
func b() -> Return
}
extension FirstProtocol {
func a() -> Return {
print("protocol a hello")
return self.b()
}
func b() -> Return {
print("protocol b hello")
return Return0(5)
}
}
enum Selector {
case first, second
func cls() -> FirstProtocol{
switch self {
case .first:
return First1Class()
case .second:
return First2Class()
}
}
}
final class First1Class: FirstProtocol {
init() {
}
func b() -> Return1 {
print("first 1 class hello")
return Return1(3)
}
}
final class First2Class: FirstProtocol {
init() {
}
func b() -> Return2 {
print("first 2 class hello")
return Return2(5)
}
}
final class Runner {
var cls: FirstProtocol
var selector: Selector
init(_ selector: Selector) {
self.cls = selector.cls()
self.selector = selector
}
func createCls(cls: FirstProtocol.Type) -> FirstProtocol {
return cls.init()
}
func run(cls: FirstProtocol.Type) {
print("--- run 1 ---")
(self.createCls(cls: cls) as! First2Class).a()
}
func run2(t: Selector) -> Return {
print("--- run 2 ---")
print(t.cls())
return t.cls().b()
}
func run3() -> Return {
print("--- run 3 ---")
print(self.cls)
return self.cls.a()
}
}
final class Runner2 {
var runner: Runner
init(runner: Runner) {
self.runner = runner
}
func run() -> Return {
print("--- 2run 1 ---")
return self.runner.run2(t: .second)
}
}
var a = Runner2(runner: Runner(.second)).run()
print(type(of: a))
print(a.value)
And returns below result.
--- 2run 1 --- line 1
--- run 2 --- line 2
__lldb_expr_80.First2Class line 3
protocol b hello line 4
return 0 line 5
Return0 line 6
5 line 7
And here I have a question.
In line 3 which is result of Runner.run2, I think __lldb_expr_80.First2Class string means compiler exactly knows which class should be initiated. Therefore line 4 should be first 2 class hello not protocol b hello. Why protocol b hello is printed and how to make first 2 class hello is printed?
This is because the b in First2Class is not actually a witness for the b requirement in the FirstProtocol (same goes for First1Class). In other words, the reason why First2Class conforms to FirstProtocol is not the b method declared in it. The only witness for the protocol requirement is only the b in the protocol extension.
This is because the return types of these bs don't match the protocol requirement's return type:
// protocol requirement
func b() -> Return {
...
}
// First1Class
func b() -> Return1 {
...
}
// First2Class
func b() -> Return2 {
...
}
Return types must match exactly in order for a type to implement a protocol. See more discussions here.
When you call b on a protocol type, such as here:
return t.cls().b()
(t.cls() is of compile-time type FirstProtocol) because the bs are not the witness, your bs do not get considered when resolving the call. The call will only resolve to the only witness, which is the b in the protocol extension.
...means compiler exactly knows which class should be initiated.
That's not true. Remember that you only see the message printed at runtime. The compiler doesn't know which class is instantiated by cls.
Here is a shorter example that demonstrates this:
class A {}
class B : A {}
protocol Foo {
func foo() -> A
}
extension Foo {
func foo() -> A {
print("Foo")
return A()
}
}
class Bar : Foo {
func foo() -> B {
print("Bar")
return B()
}
}
let foo: Foo = Bar()
let bar = Bar()
foo.foo() // prints Foo
bar.foo() // prints Bar

How to pass a function as an optional parameter Swift

New to Swift and I am currently getting around passing a function as an optional parameter in the following way:
import Foundation
func foo()
{
print("Foo")
}
func bar()
{
print("Bar")
}
func dummy()
{
return
}
func myFunc()
{
myFunc(callBack: dummy())
}
func myFunc(callBack: (Void))
{
foo()
callBack
}
myFunc()
myFunc(callBack: bar())
i.e. exploiting polymorphism
This seems like an inelegant way to do this, is there a better way,
Thanks,
Tom
edit:
I am aware I could shorten this by doing:
import Foundation
func foo()
{
print("Foo")
}
func bar()
{
print("Bar")
}
func dummy()
{
return
}
func myFunc(callBack: (Void) = dummy())
{
foo()
callBack
}
myFunc()
myFunc(callBack: bar())
But I would still say this is an inelegant solution
You can easily define a default value for a function as parameter:
func foo(completion: () -> Void = { }) {
completion()
}
You could also have it be nil by default:
func foo(completion: (() -> Void)? = nil) {
When it's an optional closure, you'll have to call it like this:
completion?()
Your are referring to default arguments:
You can define a default value for any parameter in a function by assigning a value to the parameter after that parameter’s type. If a default value is defined, you can omit that parameter when calling the function.
So you need something like:
func myfunc (callback: ()->void = dummy) {
LinusGeffarth notes that callbacks in Swift are called completion, or closure as avismara notes.
Full code with answer applied:
import Foundation
func foo()
{
print("Foo")
}
func bar()
{
print("Bar")
}
func myFunc(completion: () -> Void = { })
{
foo()
completion()
}
myFunc()
myFunc(completion: bar)
Umm, are you passing function as an optional parameter, though? It looks like you have written a method that accepts Void, you have a function that accepts Void and you are just calling that method. I don't see any trace of polymorphism here except probably that the myFunc has multiple signatures. This method is an inelegant solution not because it is inelegant, but because it isn't a solution.
Here is a correct example of polymorphism in functional systems:
func printA() {
print("A")
}
func printB() {
print("B")
}
//This method accepts a function as a parameter
func higherOrderPrinter(with print: () -> Void ) {
print() //Can be anything, depends on the method you send here. Polymorphism much? :)
}
higherOrderPrinter(with: printA) //Prints A. See carefully how I am NOT doing printA()
higherOrderPrinter(with: printB) //Prints B
//In fact...
higherOrderPrinter {
print("C")
} //Prints C

Create instance of class based on function argument [duplicate]

This question already has answers here:
Swift language NSClassFromString
(25 answers)
Closed 5 years ago.
Suppose I have three classes:
import Foundation
class A {
init() {
print("A")
}
}
class B {
init() {
print("B")
}
}
class C {
init() {
print("C")
}
}
I want to dinamically pass a string ("A", "B" or "C") as a function argument and then, inside the body of this function, create an instance of the class I passed. Is this possible? How?
I tried this one (and other variants) but with no luck:
func test(c:AnyObject){
let _class = c()
//...
}
test(c:A)
[UPDATE] Maybe the question is no different from the one #Code Different suggests but that question is old and there were so many changes in the language that one should try any suggested solution before finding the one that works as of today
What could work is having a base class, let's call it BaseClass. Classes that needs to be used would inherit from BaseClass.
Then, in your function, you would pass it the desired type.
Here is a code snippet that demonstrates this technique:
class BaseClass { }
class A: BaseClass { ... }
class B: BaseClass { ... }
class C: BaseClass { ... }
func test(type: BaseClass.Type) {
let someObject = type.init()
// You can cast the object if required
}
test(type: A.self) // creates an object of class A
test(type: B.self) // creates an object of class B
Edit: If you really need a string to cast your types, you might consider doing some job prior to calling test. Getting the type in a switch case and then passing it to test should do.
Edit: It would also work with a protocol, as long as it defines the initializers you need, along with every functions that must be exposed:
protocol SomeProtocol: class {
init()
func someFunction()
}
class A {
required init() {
print("A")
}
}
extension A: SomeProtocol {
func someFunction() {
print("Some function of A")
}
}
class B {
required init() {
print("B")
}
}
extension B: SomeProtocol {
func someFunction() {
print("Some function of B")
}
}
class C {
required init() {
print("C")
}
}
extension C: SomeProtocol {
func someFunction() {
print("Some function of C")
}
}
func test(someType: SomeProtocol.Type) {
let someObject: SomeProtocol = someType.init()
someObject.someFunction()
}
test(someType: A.self) // creates an object of class A
test(someType: B.self) // creates an object of class B

how can i use `#function` symbol in a `inline` function?

I'd like to use the name of function to resolve some problems, but #function seems not to work well with #inline(__always), here is my codes:
#inline(__always) func log() {
print(#function)
}
func a() { log() } // want 'a()', but got 'log()'
func b() { log() }
func c() { log() }
//...
Can anybody explain? or that's just a stupid idea.
If your intention is to print the name of the function which calls
log(), then you should pass it as default argument (which is evaluated
in the context of the caller), as demonstrated
in Building assert() in Swift, Part 2: __FILE__ and __LINE__ in the Swift blog.
Example:
#inline(__always) func log(_ message: String, callingFunction: String = #function) {
print("\(callingFunction): \(message)")
}
func a() { log("Hello world") }
func b() { log("Foo") }
func c() { log("Bar") }
a() // a(): Hello world
b() // b(): Foo
c() // c(): Bar
This works regardless of whether the log function is inlined or not.
(Inlining does not change the semantics of a program. In particular,
it does not mean that the source code of func log is included from
the source code of func a() and compiled as a single function.)

Overriding a function outside its class

I came across a strange behaviour. The following code produces a compile error where I call bar() with the message: "Missing argument for parameter #1 call"
func bar() {
println("bar with no argument")
}
class ClassA {
func bar(varOfAnyType: String) {
println("bar with argument")
}
func foo() {
bar()
}
}
If I change bar() function's name then I get no errors:
func barNameChanged() {
println("bar with no argument")
}
class ClassA {
func bar(varOfAnyType: String) {
println("bar with argument")
}
func foo() {
barNameChanged()
}
}
What's the reason for the compiler not allowing to override the function outside the class?
Cheers, Daniel
At the moment, the Swift compiler cannot distinguish between a method and a global function with the same name, regardless of overloading.
The solution is to prefix the global function with its module name, e.g.,
func bar() { }
class ClassA {
func bar(anything: String) {}
func foo() { Module.bar() }
}