Set struct method as callback - callback

I have some struct and want a method of this struct to be a callback. I tried to set the callback as a closure and call the method in it, but this does not work.
Here is example of what I want. In this example I use the Cursive library:
extern crate cursive;
use cursive::Cursive;
use cursive::views::{BoxView, SelectView, IdView};
use cursive::view::Selector;
struct SomeStruct {
siv: Cursive,
}
impl SomeStruct {
fn new(siv: Cursive) -> SomeStruct {
let mut ss = SomeStruct {
siv: siv
};
let mut select: SelectView<i32> = SelectView::new();
select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
ss.siv.add_fullscreen_layer(BoxView::with_full_screen(IdView::new("select", select)));
ss
}
fn on_submit_callback(&mut self, siv: &mut Cursive, value: &i32) {
println!("value - {}", value);
}
}
fn main() {
let siv = Cursive::new();
let mut ss = SomeStruct::new(siv);
}
There are compiler errors:
error[E0373]: closure may outlive the current function, but it borrows `ss`, which is owned by the current function
--> src/main.rs:20:34
|
20 | select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
| ^^^^^^^^^^^^ -- `ss` is borrowed here
| |
| may outlive borrowed value `ss`
|
help: to force the closure to take ownership of `ss` (and any other referenced variables), use the `move` keyword, as shown:
| select.set_on_submit(move |siv, value| ss.on_submit_callback(siv, value));
error[E0387]: cannot borrow data mutably in a captured outer variable in an `Fn` closure
--> src/main.rs:20:47
|
20 | select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
| ^^
|
help: consider changing this closure to take self by mutable reference
--> src/main.rs:20:34
|
20 | select.set_on_submit(|siv, value| ss.on_submit_callback(siv, value));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

Rust is not very callback-friendly, to be honest.
Callbacks are easy in garbage-collected languages, as sharing an object is an issue, but tend to be more difficult in languages where ownership is explicit. In this case, you have two possibilities:
event managers,
plowing on with shared ownership.
The latter is easy enough for small applications, but can become really messy (and leaky) at a larger scale. Still, let's start by it.
The most direct translation of Python would be to use shared ownership: a reference counted pointer Rc, wrapping some Cell or RefCell (to defer borrow-checking to run-time).
fn new(siv: Cursive) -> Rc<RefCell<SomeStruct>> {
let mut ss = Rc::new(RefCell::new(SomeStruct {
siv: siv
}));
let mut select: SelectView<i32> =
Rc::new(RefCell::new(SelectView::new()));
{
let weak = ss.clone().downgrade();
select.borrow_mut().set_on_submit(|siv, value|
weak.upgrade()
.map(|ss| ss.borrow_mut().on_submit_callback(siv, value))
);
}
ss.borrow_mut().siv.add_fullscreen_layer(
BoxView::with_full_screen(IdView::new("select", select))
);
ss
}
So, let's get our ownership story straight:
ss owns (partly) select,
select has a weak reference to ss.
The weak reference is necessary to break the cycle, as this would leak.
This solution should work, but as mentioned:
it's a bit clunky syntax-wise,
it's a bit complicated to keep track of where to use Weak to break the cycles,
if you try borrowing twice from RefCell at the same time, one borrow being mutable, you'll get a panic.
In short: it works, but it's not nice.
The other solution is to use a event manager instead.
Event loops are an easy solution to decouple ownership: instead of directly calling on_submit_callback in the callback, push an event to the event manager!
The solution is a bit more involved:
you need something to own SomeStruct (and probably other),
an ID system (you pass an ID instead of a pointer),
an event manager that can retrieve a component by ID to dispatch an event to it,
...
On the other hand, it works pretty well and a decoupled system can be easier to interact with.

Related

Capturing a property of an object for a closure in Swift

I'm rewriting some code to append jobs to an array of closures rather than execute them directly:
var someObject: SomeType?
var jobsArray: [() -> ()] = []
// before rewriting
doExpensiveOperation(someObject!.property)
// 1st attempt at rewriting
jobsArray.append {
doExpensiveOperation(someObject!.property)
}
However, because the value of someObject might change before the closure is executed, I'm now adding a closure list as follows:
// 2nd attempt at rewriting
jobsArray.append { [someObject] in
doExpensiveOperation(someObject!.property)
}
Hopefully then if, say, someObject is subsequently set to nil before the closure executes, the closure will still access the intended instance.
But what's the neatest way to deal with the possibility that the value of .property might change before the closure is executed? Is there a better way than this?
// 3rd attempt at rewriting
let p = someObject!.property
jobsArray.append {
doExpensiveOperation(p)
}
I'm not very keen on this solution because it means changing the original line of code. I'd prefer this but it doesn't work:
// 4th attempt at rewriting
jobsArray.append { [someObject!.property] in
doExpensiveOperation(someObject!.property)
}
Pretty new to Swift, so all guidance gratefully received. Thanks!
A capture list such as [someObject] is actually syntactic sugar for [someObject = someObject], where the right hand side can be an arbitrary expression that gets bound to a new constant upon the closure being formed.
Therefore one option is to write your example as:
jobsArray.append { [property = someObject!.property] in
doExpensiveOperation(property)
}

Swift Closures: Must Capture Lists Be Exhaustive?

Suppose I have a Swift class like this:
#objc final MyClass : NSObject
{
let classPropertyString = "A class property"
func doStuff()
{
let localString = "An object local to this function"
DispatchQueue.global(qos: .userInitiated).async { [classPropertyString] in
// Do things with 'classPropertyString' and 'localString'
}
}
}
My question is: when I write a capture list, am I responsible for EXHAUSTIVELY listing all the things to which I want the closure to hold a strong reference?
In other words, if I omit localString from my capture list (as I've done here), will the closure still automatically capture a strong reference to it or am I in for a bad time?
There are several minor quirks with your question that make it tricky to answer clearly, but I think I understand the underlying concern, and the short answer is "no." But your example is impossible, so the answer is "it's impossible." And if it were possible, there'd be no strong reference (nor would there be a need for one), so the question still would be kind of "it's impossible." Even so, let's walk through what's going on here.
First, closure can't reference localString unless it's reassigned somehow in the comment inside doStuff(). closure is assigned at a level where localString is not in scope. Closures can only capture variables that are in scope when they are assigned, not when they're called. But let's go back to the original version of this question, before it was edited. That version did have the case you're describing:
#objc final myClass : NSObject
{
let classPropertyString = "A class property"
func doStuff()
{
let localString = "An object local to this function"
DispatchQueue.global(qos: .userInitiated).async { [classPropertyString] in // (1)
// Do things with 'classPropertyString' and 'localString'
}
// (2)
}
}
There's no problems here. classPropertyString is copied into the closure, avoiding any retain loops. localString is referenced by the closure, and so it's preserved as long as the closure exists.
Because you listed classPropertyString in the capture list, it is evaluated at point (1) and copied into the closure. Because you implicitly captured localString, it is treated as a reference. See Capture Lists in the Swift Programming Language Reference for some excellent examples of exactly how this works in different cases.
In no case (*) will Swift allow the underlying storage for something you're using in a closure to disappear behind your back. That's why the typical concern is excessive retains (memory leaks) rather than dangling references (crashes).
(*) "In no case" here is a lie. There are several ways that Swift will allow it, but almost all of them involve "Unsafe" which is your warning about that. The major exception is unowned, and of course anything involving ! types. And Swift is not typically thread-safe, so you need to be careful about that...
The last comment about thread-safety is a place where the subtle distinctions between implicit and explicit captures can really matter. Consider this case where you modify an implicitly captured value on two queues:
func doStuff() -> String
{
var localString = "An object local to this function"
DispatchQueue.global(qos: .userInitiated).async {
localString = "something else"
callFunction(localString)
}
localString = "even more changes"
return localString
}
What happens in that case? Good grief, never do that. I believe it's undefined behavior and that localString could be anything including corrupted memory, at least in the most general case (it might be defined behavior for calling .async; I'm not sure). But don't do it.
But for your normal cases, there is no reason to explicitly capture local variables. (I sometimes wish Swift had gone the C++ way and said it was required, but it isn't.)
Ok, one more way implicit and explicit are different that might drive home how they work. Consider a stateful closure like this (I build these pretty often):
func incrementor() -> () -> Int {
var n = 0
return {
n += 1
return n
}
}
let inc = incrementor()
inc() // 1
inc() // 2
inc() // 3
let inc2 = incrementor()
inc2() // 1
See how the local variable n is captured by the closure, and can be modified after it goes out of scope. And see how inc2 has its own version of that local variable. Now try that with explicit capture.
func incrementor() -> () -> Int {
var n = 0
return { [n] in // <---- add [n]
n += 1 // Left side of mutating operator isn't mutable: 'n' is an immutable capture
return n
}
}
Explicit captures are copies and they're immutable. Implicit captures are references, and so have the same mutability as the thing they reference.

Why is the capture specifier optional in capture lists?

There seems to be a curious syntax glitch in the capture list syntax in Swift. If I declare multiple captured variables, the capture specifier only applies to the first one:
let closure = { [unowned x, y] in … }
Now I would expect y to be unowned, but it doesn’t seem to be the case:
class Test {
var callback: (Void -> Void)?
init() {
print("init")
}
deinit {
print("deinit")
}
}
func makeScope() {
let x = Test()
let y = Test()
y.callback = { [unowned x, y] in
print(y)
}
}
makeScope()
print("done")
This prints:
init
init
deinit
done
So y seems to be captured strongly and creates a retain cycle, preventing the object from being deallocated. Is that so? If yes, does it make sense to permit an “empty” capture specifier in the list? Or is there a reason [unowned x, y] is not treated as [unowned x, unowned y]?
... does it make sense to permit an “empty” capture specifier in the list?
Yes it does.
The capture specifiers ("weak", "unowned" and its variations) can only be used with reference types, but there are also cases where you want to capture a value type
(here is one example:
Pass value to closure?).
You also may want to capture a reference type strongly.
Capturing a reference type ensures that the reference (pointer)
itself is captured by value, as demonstrated in the following example:
class MyClass {
let value : String
init(value : String) {
self.value = value
}
}
var ref = MyClass(value: "A")
let clo1: () -> Void = { print(ref.value) }
let clo2: () -> Void = { [ref] in print(ref.value) }
ref = MyClass(value: "B")
clo1() // Output: B
clo2() // Output: A
When the first closure is executed, ref inside the closure
is a reference to the object created as MyClass(value: "B").
The second closure captures the value of ref at the time the
closure is created, and this does not change when a new value
is assigned to var ref.
According to the syntax EBNF, this treatment of unowned capture specifier is fully intentional:
closure-signature → parameter-clause­ function-result­opt in­
closure-signature → identifier-list­ function-result­opt ­in­
closure-signature → capture-list­ parameter-clause ­function-resultopt in­
closure-signature → capture-list ­identifier-list ­function-result­opt ­in­
closure-signature → capture-list­ in­
capture-list → [­capture-list-items­]­
capture-list-items → capture-list-item­ capture-list-item ,­ ­capture-list-items­
capture-list-item → capture-specifieropt ­expression­
capture-specifier → weak­ | unowned­ | unowned(safe)­ | unowned(unsafe)­
The three lines at the bottom defining <capture-list-items>, <capture-list-item>, and <capture-specifier> productions are most relevant here.
The <capture-list-items> production is a comma-separated list of <capture-list-item>, with the capture-specifier is attached to each individual <capture-list-item>, not to <capture-list-items> list as a whole.
This makes perfect sense, because it gives programmers full control over capturing of individual arguments. The alternative when the specifier would apply to the whole list would take away this flexibility.
why would one want to include an identifier in the capture list without modifying its capture specifier?
It appears that the philosophy of Swift's designers is to provide smart default behaviors whenever it is possible. In most cases, Swift can figure out a way to capture an expression that makes most sense based on the type of the expression without any involvement from the programmer. Explicit capture specifier is left for exceptional situations, when the compiler does not have enough information to figure out the proper way of capturing a variable based on the context.
To answer your specific questions:
Why is the capture specifier optional in capture lists?
Because the default behavior is to capture any necessary variables (reference types are captured strongly). By default, you don't need to specify them explicitly in the capture list if you want to use their values. (Although qualifying with self.property will be necessary if you are capturing self.)
…is there a reason [unowned x, y] is not treated as [unowned x, unowned y]?
For the same reason: the default is to capture strongly. The unowned doesn't apply to other items in the capture list; that's just not how the syntax works right now.

How to share stream position betwixt functions in Swift?

I was surprised by the following playground I created after seeing some unexpected behavior in my code:
import Foundation
let bytes:[UInt8] = [20, 30, 40, 50, 60, 70]
var stream = bytes.generate()
func consumeTwo(var stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(stream) // This prints 20 and 30
print(stream.next()) // This prints 20!? I expected 40!
I had thought that marking the stream argument as var to the consumeTwo() function, the stream state/position would be shared/updated as it moved from function to function. But that appears to not be the case.
Does this mean I need to make that an inout? And pass with the ampersand? When does one use the var if that's the case?
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
+1 for archaic English in the question title. :)
When you use var in a function signature, you create a local copy of that value. It's the same as if you did this:
func consumeTwo(stream: IndexingGenerator<[UInt8]>) {
var localStream = stream
print(localStream.next())
print(localStream.next())
}
When the parameter is a reference type (i.e. a class), the duplicate "value" is a duplicate reference to the same object. But the thing you get from Array.generate() is a value type, so your local copy is a separate iterator with separate state.
Does this mean I need to make that an inout? And pass with the ampersand?
Yes — for your simple example, inout (and pass with &) is a simple and idiomatic way to do this:
func consumeTwo(inout stream:IndexingGenerator<[UInt8]>) {
print(stream.next())
print(stream.next())
}
consumeTwo(&stream) // This prints 20 and 30
print(stream.next()) // This prints 40
Remember: when you want to modify a value type inside a function and later see those modifications outside the function, use inout. And the & goes with it, so that it's clear both inside the function and at the call site that this behavior is happening.
When does one use the var if that's the case?
Use var for parameters only when you want to make a copy that's local to the function invocation. Admittedly, the use cases for this are few. Here's a contrived (and completely unnecessary) one:
func bananify(var strings: [String]) {
for i in 1.stride(to: strings.count, by: 2) {
strings[i] = "banana"
}
print(strings.joinWithSeparator(" "))
}
let words = ["foo", "bar", "bas", "zap", "asdf"]
bananify(words) // "foo banana bas banana asdf\n"
If you find this confusing, you're not the only one. For this reason, removing the ability to use var for parameters is a planned change for Swift 3.
More generally... what is the right/idiomatic way to create a stream over a byte array which can be passed from function to function (e.g. a decoder) and preserve the position of the stream as it is passed around?
As user3441734 notes, you can indeed create and use a reference-type iterator instead. Or you can write a reference type that holds and manages an iterator. For your hypothetical case of sharing a stream among several subsystems of a program, this is probably a good approach — representing a shared resource is one of the canonical cases for using reference types.
you wrote "It makes me wish that Generators were objects instead of structs."
there is no trouble define some generator as reference type ...
class G: AnyGenerator<Int> {
var i = 0
override func next() -> Int? {
return i++
}
}
let g = G()
func foo(gen: G)->Void {
print(gen.next())
print(gen.next())
}
foo(g)
print(g.next())
/*
Optional(0)
Optional(1)
Optional(2)
*/

Syntactic Sugar Struct Reference in Swift?

In c++, one can introduce an alias reference as follows:
StructType & alias = lengthyExpresionThatEvaluatesToStuctType;
alias.anAttribute = value; // modify "anAttribute" on the original struct
Is there a similar syntactic sugar for manipulating a (value typed) struct in Swift?
Update 1: For example: Let say the struct is contained in a dictionary of kind [String:StructType], and that I like to modify several attributes in the the struct myDict["hello"]. I could make a temporary copy of that entry. Modify the copy, and then copy the temporary struct back to the dictionary, as follows:
var temp = myDict["hello"]!
temp.anAttribute = 1
temp.anotherAttribute = "hej"
myDict["hello"] = temp
However, if my function has several exit points I would have to write myDict["hello"] = temp before each exit point, and it would therefore be more convinient if I could just introduce and alias (reference) for myDict["hello"] , as follows:
var & alias = myDict["hello"]! // how to do this in swift ???
alias.anAttribute = 1
alias.anotherAttribute = "hej"
Update 2: Before down- or close- voting this question: Please look at Building Better Apps with Value Types in swift (from WWWDC15)!! Value type is an important feature of Swift! As you may know, Swift has borrowed several features from C++, and value types are maybe the most important feature of C++ (when C++ is compared to Java and such languages). When it comes to value types, C++ has some syntactic sugar, and my questions is: Does Swift have a similar sugar hidden in its language?. I am sure Swift will have, eventually... Please, do not close-vote this question if you do not understand it!
I have just read Deitel's book on Swift. While I'am not an expert (yet) I am not completely novel. I am trying to use Swift as efficient as possible!
Swift doesn't allow reference semantics to value types generally speaking, except when used as function parameters declared inout. You can pass a reference to the struct to a function that works on an inout version (I believe, citation needed, that this is implemented as a copy-write, not as a memory reference). You can also capture variables in nested functions for similar semantics. In both cases you can return early from the mutating function, while still guaranteeing appropriate assignment. Here is a sample playground that I ran in Xcode 6.3.2 and Xcode 7-beta1:
//: Playground - noun: a place where people can play
import Foundation
var str = "Hello, playground"
struct Foo {
var value: Int
}
var d = ["nine": Foo(value: 9), "ten": Foo(value: 10)]
func doStuff(key: String) {
let myNewValue = Int(arc4random())
func doMutation(inout temp: Foo) {
temp.value = myNewValue
}
if d[key] != nil {
doMutation(&d[key]!)
}
}
doStuff("nine")
d // d["nine"] has changed... unless you're really lucky
// alternate approach without using inout
func doStuff2(key: String) {
if var temp = d[key] {
func updateValues() {
temp.value = Int(arc4random())
}
updateValues()
d[key] = temp
}
}
doStuff2("ten")
d // d["ten"] has changed
You don't have to make the doMutation function nested in your outer function, I just did that to demonstrate the you can capture values like myNewValue from the surrounding function, which might make implementation easier. updateValues, however, must be nested because it captures temp.
Despite the fact that this works, based on your sample code, I think that using a class here (possibly a final class if you are concerned about performance) is really more idiomatic imperative-flavored Swift.
You can, if you really want to, get a raw pointer using the standard library function withUnsafeMutablePointer. You can probably also chuck the value into an inner class that only has a single member. There are also functional-flavored approaches that might mitigate the early-return issue.