How can I check all historic values in a ReplaySubject in RxSwift? - rx-swift

I have a simple struct Foo:
struct Foo {
let bar: String
}
Now I create an unbounded ReplaySubject of Foos:
let subject = ReplaySubject<Foo>.createUnbounded()
How can I now understand whether the (unterminated) stream has a Foo whose bar was equal to abc? (This could be the 1st, 3rd, or 20th element.)

First, this is kind of a crazy request. You should not be thinking about "what was" when working with Rx. Rather you should be thinking about what is always the case. You should be thinking about invariants...
That said, the operator below will emit the indexes for you. Since the subject is able to constantly emit events, the operator is designed to work in real time. It can be used like this:
let indexes = subject.indexOfElementSatisfying { $0.bar == "abc" }
Here it is:
extension ObservableConvertibleType {
/**
Emits the index of all the values in the stream that satisfy the predicate.
- parameter pred: The predicate that determines whether the value satisfies the condition
- returns: An observable sequence of indexes to those elements.
*/
func indexOfElementSatisfying(_ pred: #escaping (E) throws -> Bool) -> Observable<Int> {
return asObservable()
.enumerated()
.filter { try pred($0.element) }
.map { $0.index }
}
}

Related

Is there some syntactic sugar for matching on deeply nested Option and Result chains?

I am issuing calls that return an Option that contains a Result which contains another Option that contains custom variants.
I am only ever interested in a specific chain of variant results like this:
if let Some(Ok(Some(CustomVariant(Some(value))))) = expr {
// handle value case
}
This is getting quite verbose and not really helpful, since I actually treat it as a single Result in all of my code. Can I somehow alias this code so that instead of writing the entire chain of Options and Results I can do something similar to:
alias TheCase(value) = Some(Ok(Some(CustomVariant(Some(value))));
if let TheCase(value) = expr {
//handle value
}
You don't need such an alias, just use a function to retrieve the one case you want:
fn oneCaseICareAbout(value: &Option<Result<Option<Foo>, Bar>>) -> Option<&Foo> {
if let Some(Ok(Some(CustomVariant(Some(value)))) = value {
Some(value)
} else {
None
}
}
if let Some(value) = oneCaseICareAbout(expr) {
//handle value
}
I would however consider refactoring your code not to use such a type. Option<Result<_, _>> is already a red flag, but Some(Ok(Some(CustomVariant(Some(…)))) is just on the edge of insanity!

RxSwift: Convert Observable to a Variable

How do I convert an Observable of type Int to a Variable of type Int?
Here is what I have tried so far:
let obs: Observable<Int> = Observable.of(4)
let variable: Variable<Int> = obs
.flatMap { num in
return Variable<Int>(num)
}
Using flatMap feels like the most logical way of doing the conversion, however, I get a compiler error which essentially says that it does not like the flatMap returning anything that is not an observable. Any ideas?
EDIT:
Just to give some context as to why I need to convert the Observable into a Variable:
I need my viewModel to drive a UIPickerView inside a ViewController. Currently, I have two exposed properties in my ViewModel, items: Observable<[String]> (which is the datasource for the UIPickerView) and selectedIndex: Variable. The selectedIndex will drive the initial value of the UIPickerView but also keep track of any changes the user makes.
The reason I needed to convert from the Observable to Variable was that I needed to figure out which index of the UIPickerView should be selected initially:
items.map { days -> Int in
if let index = days.index(where: { str in
return str == selectedDay
}) {
return index
}
return 0
}
.flatMap { num in
return Variable<Int>(num)
}
I'm now wondering if I'm over complicating things, and if instead of the Variable in I should just have an Observable.
A few points here:
First, You should not use Variable as it's deprecated (gonna be entirely deprecated in Swift 5 probably). Look at BehaviorSubject and BehaviorRelay instead.
About your question, I'm not sure what is the use case for having a Variable equal to an Observable, so there are two different thoughts I have:
You can bind an Observable to a Variable/Subject/Relay (e.g. observable.bind(to: variable))
You can actually go the other way around an get an Observable from the Variable, which might make more sense. e.g. variable.asObservable()

Composing Option<Enum> with closures that pattern-match arguments

I have an enum with two different possible "types" and a function that may return any of them, wrapped in an Option:
enum Possibilities {
First(i32),
Second(String),
}
use Possibilities::*;
fn some_poss() -> Option<Possibilities> {
Some(Second(String::from("hi")))
}
I want to apply an operation to the result of some_poss, but this operation only makes sense for one of the possibilities of the enum, otherwise it should return None. For example:
let a: Option<i32> = some_poss().and_then(|poss| if let First(x) = poss {
Some(x * 2)
} else {
None
});
How can I concisely combine this operation? Would it be possible to write this in a way similar to the following?
// Compile error: pattern `Second(_)` not covered
let b: Option<i32> = some_poss().map(|First(x)| x * 2);
The best way to handle this specific case would be to create a method on the enum specifically for retrieving the one variant. Somewhat like Result::ok.
enum Possibilities {
First(i32),
Second(String),
}
use Possibilities::*;
impl Possibilities {
fn first(self) -> Option<i32> {
match self {
Possibilities::First(x) => Some(x),
_ => None,
}
}
}
This would allow you to implement your function like:
some_fun().and_then(|p| p.first()).map(|x| x * 2)
// or, if you prefer this style:
some_fun().and_then(Possibilities::first).map(|x| x * 2);
This makes it explicit what each step is doing - some_poss gets an Option<Possiblities>, then first() gets an Option<i32> from that Possibilities, and then and_then collapses Option<Option<i32>> into Option<i32>.

Pattern matching over borrowed HashMap containing enums

I'm trying to learn Rust, so bear with me if I'm way off :-)
I have a program that inserts enums into a HashMap, and uses Strings as keys. I'm trying to match over the content of the HashMap. Problem is that I can't figure out how to get the correct borrowings, references and types in the eval_output function. How should the eval_output function look to properly handle a reference to a HashMap? Is there any good document that I can read to learn more about this particular subject?
use std::prelude::*;
use std::collections::HashMap;
enum Op {
Not(String),
Value(u16),
}
fn eval_output(output: &str, outputs: &HashMap<String, Op>) -> u16 {
match outputs.get(output) {
Some(&op) => {
match op {
Op::Not(input) => return eval_output(input.as_str(), outputs),
Op::Value(value) => return value,
}
}
None => panic!("Did not find input for wire {}", output),
}
}
fn main() {
let mut outputs = HashMap::new();
outputs.insert(String::from("x"), Op::Value(17));
outputs.insert(String::from("a"), Op::Not(String::from("x")));
println!("Calculated output is {}", eval_output("a", &outputs));
}
Review what the compiler error message is:
error: cannot move out of borrowed content [E0507]
Some(&op) => {
^~~
note: attempting to move value to here
Some(&op) => {
^~
help: to prevent the move, use `ref op` or `ref mut op` to capture value by reference
While technically correct, using Some(ref op) would be a bit silly, as the type of op would then be a double-reference (&&Op). Instead, we simply remove the & and have Some(op).
This is a common mistake that bites people, because to get it right you have to be familiar with both pattern matching and references, plus Rust's strict borrow checker. When you have Some(&op), that says
Match an Option that is the variant Some. The Some must contain a reference to a value. The referred-to thing should be moved out of where it is and placed into op.
When pattern matching, the two keywords ref and mut can come into play. These are not pattern-matched, but instead they control how the value is bound to the variable name. They are analogs of & and mut.
This leads us to the next error:
error: mismatched types:
expected `&Op`,
found `Op`
Op::Not(input) => return eval_output(input.as_str(), outputs),
^~~~~~~~~~~~~~
It's preferred to do match *some_reference, when possible, but in this case you cannot. So we need to update the pattern to match a reference to an Op — &Op. Look at what error comes next...
error: cannot move out of borrowed content [E0507]
&Op::Not(input) => return eval_output(input.as_str(), outputs),
^~~~~~~~~~~~~~~
It's our friend from earlier. This time, we will follow the compilers advice, and change it to ref input. A bit more changes and we have it:
use std::collections::HashMap;
enum Op {
Not(String),
Value(u16),
}
fn eval_output(output: &str, outputs: &HashMap<String, Op>) -> u16 {
match outputs.get(output) {
Some(op) => {
match op {
&Op::Not(ref input) => eval_output(input, outputs),
&Op::Value(value) => value,
}
}
None => panic!("Did not find input for wire {}", output),
}
}
fn main() {
let mut outputs = HashMap::new();
outputs.insert("x".into(), Op::Value(17));
outputs.insert("a".into(), Op::Not("x".into()));
println!("Calculated output is {}", eval_output("a", &outputs));
}
There's no need to use std::prelude::*; — the compiler inserts that automatically.
as_str doesn't exist in stable Rust. A reference to a String (&String) can use deref coercions to act like a string slice (&str).
I used into instead of String::from as it's a bit shorter. No real better reason.

Variable capture by closures in Swift and inout parameters

I noticed that when a variable is captured by a closure in Swift, the closure can actually modify the value. This seems crazy to me and an excellent way of getting horrendous bugs, specially when the same var is captured by several closures.
var capture = "Hello captured"
func g(){
// this shouldn't be possible!
capture = capture + "!"
}
g()
capture
On the other hand, there's the inout parameters, which allow a function or closure to modify its parameters.
What's the need for inout, even captured variables can already be modified with impunity??!!
Just trying to understand the design decisions behind this...
Variables from an outer scope that are captured aren't parameters to the routine, hence their mutablility is inherited from context. By default actual parameters to a routine are constant (let) and hence can't be modified locally (and their value isn't returned)
Also note that your example isn't really capturing capture since it's a global variable.
var global = "Global"
func function(nonmutable:Int, var mutable:Int, inout returnable:Int) -> Void {
// global can be modified here because it's a global (not captured!)
global = "Global 2"
// nomutable can't be modified
// nonmutable = 3
// mutable can be modified, but it's caller won't see the change
mutable = 4
// returnable can be modified, and it's caller sees the change
returnable = 5
}
var nonmutable = 1
var mutable = 2
var output = 3
function(nonmutable, mutable, &output)
println("nonmutable = \(nonmutable)")
println("mutable = \(mutable)")
println("output = \(output)")
Also, as you can see, the inout parameter is passed differently so that it's obvious that on return, the value may be different.
David's answer is totally correct, but I thought I'd give an example how capture actually works as well:
func captureMe() -> (String) -> () {
// v~~~ This will get 'captured' by the closure that is returned:
var capturedString = "captured"
return {
// The closure that is returned will print the old value,
// assign a new value to 'capturedString', and then
// print the new value as well:
println("Old value: \(capturedString)")
capturedString = $0
println("New value: \(capturedString)")
}
}
let test1 = captureMe() // Output: Old value: captured
println(test1("altered")) // New value: altered
// But each new time that 'captureMe()' is called, a new instance
// of 'capturedString' is created with the same initial value:
let test2 = captureMe() // Output: Old value: captured
println(test2("altered again...")) // New value: altered again...
// Old value will always start out as "captured" for every
// new function that captureMe() returns.
The upshot of that is that you don't have to worry about the closure altering the captured value - yes, it can alter it, but only for that particular instance of the returned closure. All other instances of the returned closure will get their own, independent copy of the captured value that they, and only they, can alter.
Here are a couple of use cases for closures capturing variables outside their local context, that may help see why this feature is useful:
Suppose you want to filter duplicates out of an array. There’s a filter function that takes a filtering predicate and returns a new array of only entries matching that predicate. But how to pass the state of which entries have already been seen and are thus duplicates? You’d need the predicate to keep state between calls – and you can do this by having the predicate capture a variable that holds that state:
func removeDupes<T: Hashable>(source: [T]) -> [T] {
// “seen” is a dictionary used to track duplicates
var seen: [T:Bool] = [:]
return source.filter { // brace marks the start of a closure expression
// the closure captures the dictionary and updates it
seen.updateValue(true, forKey: $0) == nil
}
}
// prints [1,2,3,4]
removeDupes([1,2,3,1,1,2,4])
It’s true that you could replicate this functionality with a filter function that also took an inout argument – but it would be hard to write something so generic yet flexible as the possibilities with closures. (you could do this kind of filter with reduce instead of filter, since reduce passes state from call to call – but the filter version is probably clearer)
There is a GeneratorOf struct in the standard library that makes it very easy to whip up sequence generators of various kinds. You initialize it with a closure, and that closure can capture variables to use for the state of the generator.
Suppose you want a generator that serves up a random ascending sequence of m numbers from a range 0 to n. Here’s how to do that with GeneratorOf:
import Darwin
func randomGeneratorOf(#n: Int, #from: Int) -> GeneratorOf<Int> {
// state variable to capture in the closure
var select = UInt32(n)
var remaining = UInt32(from)
var i = 0
return GeneratorOf {
while i < from {
if arc4random_uniform(remaining) < select {
--select
--remaining
return i++
}
else {
--remaining
++i
}
}
// returning nil marks the end of the sequence
return nil
}
}
var g = randomGeneratorOf(n: 5, from: 20)
// prints 5 random numbers in 0..<20
println(",".join(map(g,toString)))
Again, it’s possible to do this kind of thing without closures – in languages without them, you’d probably have a generator protocol/interface and create an object that held state and had a method that served up values. But closure expressions allow a flexible way to do this with minimal boiler plate.
A closure being able to modify the captured variable in the outer scope is pretty common across languages. This is the default behavior in C#, JavaScript, Perl, PHP, Ruby, Common Lisp, Scheme, Smalltalk, and many others. This is also the behavior in Objective-C if the outer variable is __block, in Python 3 if the outer variable is nonlocal, in C++ if the outer variable is captured with &

Resources