Swift Combine create a custom Subject - swift

I would like to have one Subject (similar to CurrentValueSubject) I can publish into, but that validates the value I'm sending. For example, I would like to validate that the input is forced between a range of values, like 1 and 10. If higher than the max, pass the maximum, if lower then the min, pass the minimum.
Please don't tell me to filter the result on the subscribing code because that's what I'm trying to avoid. That duplication.
Pseudo code would be:
let intSubject = ValidatedValueSubject<Int>(value: 5, min: 1, max: 10)
intSubject.sink { value in print(value) }
intSubject.send(-10)
intSubject.send(5)
intSubject.send(15)
I would like this to produce:
5
1
5
10
Obviously with CurrentValueSubject I can't achieve that effect.
I tried to create my own custom Subject but I can't seem to make it work.
Something tells me I should look at my problem differently because I guess this is too easy to need a custom Subject.
The use case:
I have a settings class which is updated on a Settings screen, and everywhere else, when the value change I want the screens to react accordingly. The ValidatedValueSubject lives inside this Settings object.
The Settings need to expose the Subject so any screens can react upon changes to the property.
My approach to the custom Subjectis as follows:
final class QualitySubject: Subject {
public typealias Output = Int
public typealias Failure = Never
public private(set) var value: Output
private let max: Output
private let min: Output
init(value: Output, max: Output, min: Output) {
self.min = min
self.max = max
self.value = value
self.value = validated(value)
}
private func validated(_ value: Output) -> Int {
return max(min, min($0, max))
}
var subscription: [???? QualitySubscription ?????] = []
public func send(_ value: Output) {
self.value = validated(value)
subscription.subscriber.receive(value)
}
public func send(completion: Subscribers.Completion<Failure>) {
print("completion")
}
public func send(subscription: Subscription) {
print("send subscription")
}
public func receive<S>(subscriber: S) where S : Subscriber, S.Failure == Failure, S.Input == Output {
let qualitySubscription = QualitySubscription(value: value, subscriber: subscriber)
subscriber.receive(subscription: qualitySubscription)
// I think I should save a reference to the subscription so I could forward new values afterwards (on send method) but I can't because of generic constraints.
}
}

You can wrap a CurrentValueSubject:
class MySubject<Output, Failure: Error>: Subject {
init(initialValue: Output, groom: #escaping (Output) -> Output) {
self.wrapped = .init(groom(initialValue))
self.groom = groom
}
func send(_ value: Output) {
wrapped.send(groom(value))
}
func send(completion: Subscribers.Completion<Failure>) {
wrapped.send(completion: completion)
}
func send(subscription: Subscription) {
wrapped.send(subscription: subscription)
}
func receive<Downstream: Subscriber>(subscriber: Downstream) where Failure == Downstream.Failure, Output == Downstream.Input {
wrapped.subscribe(subscriber)
}
private let wrapped: CurrentValueSubject<Output, Failure>
private let groom: (Output) -> Output
}
And use it like this:
let subject = MySubject<Int, Never>(initialValue: 5) { max(1, min($0, 10)) }
let ticket = subject.sink { print("value: \($0)") }
subject.send(-10)
subject.send(5)
subject.send(15)
Output:
value: 5
value: 1
value: 5
value: 10

Appreciating the academic aspect of wrapping a subject. However from objective point of view i'm going to offer an alternative - instead of a filter i would be using map to force value into defined boundaries.
import Combine
let subject = CurrentValueSubject<Int, Never>(5)
subject.map { max(1, min($0, 10)) }.sink {
print("value: \($0)")
}
subject.send(-10)
subject.send(5)
subject.send(15)
Same output as with the accepted answer.
value: 5
value: 1
value: 5
value: 10

Related

Swift PropertyWrapper for waiting on a value to set for the first time not working

I intend to wait for the value is set for the first time and then the get method should return. But I am getting wrong result on the first time. Here is the code
import Foundation
import OSLog
#propertyWrapper
struct WaitTillSet<T> {
private var value: T
private let group: DispatchGroup
init(wrappedValue value: T) {
self.group = DispatchGroup()
self.value = value
group.enter()
}
var wrappedValue: T {
get { getValue() }
set { setValue(newValue: newValue) }
}
mutating func setValue(newValue: T) {
value = newValue
group.leave()
}
func getValue() -> T {
group.wait()
return value
}
}
let logger = Logger()
func testFunc() {
#WaitTillSet var data = 0
DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 2) {
logger.info("Setting value to 10")
data = 10
}
logger.info("data = \(data)")
logger.info("dataAgain = \(data)")
}
testFunc()
And here is the output
2022-08-23 10:57:39.867967-0700 Test[68117:4747009] Setting value to 10
2022-08-23 10:57:39.868923-0700 Test[68117:4746644] data = 0
2022-08-23 10:57:39.869045-0700 Test[68117:4746644] dataAgain = 10
Program ended with exit code: 0
I also tried DispatchSemaphore. That gives the same result. Instead of propertyWrapper if I use class in the similar way I see the same problem. There is something fundamentally wrong with this.

When declaring static variable for conformance to AdditiveArithmetic, cannot call instance member from same type

I know this sounds crazy for a 10-year-old, but because S4TF doesn't work for me, I'm building my own neural network library in Swift. (I haven't gotten that far.) I'm creating a structure that conforms to AdditiveArithmetic. It also uses Philip Turner's Differentiable, but that's unimportant.
Anyway, when defining the zero variable, I call another variable dimen, defined in the same structure. This raises an error: instance member 'dimen' cannot be used on type 'Electron<T>'
note: the structure I am creating is going to be used to create a multi-dimensional array for neural networks.
Total code (stripped down to remove unimportant bits):
public struct Electron<T> where T: ExpressibleByFloatLiteral, T: AdditiveArithmetic {
var energy: [[Int]: T] = [:]
var dimen: [Int]
public init(_ dim: [Int], with: ElectronInitializer) {
self.dimen = dim
self.energy = [:]
var curlay = [Int](repeating: 0, count: dimen.count)
curlay[curlay.count-1] = -1
while true {
var max: Int = -1
for x in 0..<curlay.count {
if curlay[curlay.count-1-x] == dimen[curlay.count-1-x]-1 {
max = curlay.count-1-x
}
else {break}
}
if max == 0 {break}
else if max != -1 {
for n in max..<curlay.count {
curlay[n] = -1
}
curlay[max-1] += 1
}
curlay[curlay.count-1] += 1
print(curlay)
energy[curlay] = { () -> T in
switch with {
case ElectronInitializer.repeating(let value):
return value as! T
case ElectronInitializer.random(let minimum, let maximum):
return Double.random(in: minimum..<maximum) as! T
}
}()
}
}
subscript(_ coordinate: Int...) -> T {
var convertList: [Int] = []
for conversion in coordinate {
convertList.append(conversion)
}
return self.energy[convertList]!
}
public mutating func setQuantum(_ replace: T, at: [Int]) {
self.energy[at]! = replace
}
}
extension Electron: AdditiveArithmetic {
public static func - (lhs: Electron<T>, rhs: Electron<T>) -> Electron<T> where T: AdditiveArithmetic, T: ExpressibleByFloatLiteral {
var output: Electron<T> = lhs
for value in lhs.energy {
output.energy[value.key] = output.energy[value.key]!-rhs.energy[value.key]!
}
return output
}
public static var zero: Electron<T> {
return Electron.init(dimen, with: ElectronInitializer.repeating(0.0))
}
static prefix func + (x: Electron) -> Electron {
return x
}
public static func + (lhs: Electron<T>, rhs: Electron<T>) -> Electron<T> where T: AdditiveArithmetic, T: ExpressibleByFloatLiteral {
var output: Electron<T> = lhs
for value in lhs.energy {
output.energy[value.key] = output.energy[value.key]!+rhs.energy[value.key]!
}
return output
}
}
public enum ElectronInitializer {
case random(Double, Double)
case repeating(Double)
}
Error:
NeuralNetwork.xcodeproj:59:30: error: instance member 'dimen' cannot be used on type 'Electron'
return Electron.init(dimen, with: ElectronInitializer.repeating(0.0))
I don't know what's happening, but thanks in advance. I'm new to Stack Overflow, so sorry if I did something wrong.
The root of the problem is that dimen is an instance property, while zero is a static property. In a static context, you don't have an instance from which to access dimen, and so the compiler gives you the error. static properties and methods are a lot like global variables and free-functions with respect to accessing instance properties and methods. You'd have to make an instance available somehow. For a static function, you could pass it in, but for a static computed property, you'd either have to store an instance in a stored static property, which isn't allowed for generics, or you'd have to store it in a global variable, which isn't good either, and would be tricky to make work for all the possible T.
There are ways to do what you need though. They all involve implementing some special behavior for a zero Electron rather than relying on access to an instance property in your static .zero implementation. I made some off-the-cuff suggestions in comments, which would work; however, I think a more elegant solution is to solve the problem by creating a custom type for energy, which would require very few changes to your existing code. Specifically you could make an Energy type nested in your Electron type:
internal struct Energy: Equatable, Sequence {
public typealias Value = T
public typealias Key = [Int]
public typealias Element = (key: Key, value: Value)
public typealias Storage = [Key: Value]
public typealias Iterator = Storage.Iterator
public typealias Keys = Storage.Keys
public typealias Values = Storage.Values
private var storage = Storage()
public var keys: Keys { storage.keys }
public var values: Values { storage.values }
public var count: Int { storage.count }
public init() { }
public subscript (key: Key) -> Value? {
get { storage.isEmpty ? .zero : storage[key] }
set { storage[key] = newValue }
}
public func makeIterator() -> Iterator {
storage.makeIterator()
}
}
The idea here is that when energy.storage is empty, it returns 0 for any key, which allows you to use it as a .zero value. I've made it internal, because energy defaults to internal, and so I've done a minimalist job of wrapping a Dictionary, mainly providing subscript operator, and making it conform to Sequence, which is all that is needed by code you provided.
The only changes needed in the rest of your code are to change the definition of energy
var energy: Energy
Then to set it in your initializer, by-passing the bulk of your init when dim is empty.
public init(_ dim: [Int], with: ElectronInitializer) {
self.dimen = dim
self.energy = Energy() // <- Initialize `energy`
// Empty dim indicates a zero electron which doesn't need the
// rest of the initialization
guard dim.count > 0 else { return }
var curlay = [Int](repeating: 0, count: dimen.count)
curlay[curlay.count-1] = -1
while true {
var max: Int = -1
for x in 0..<curlay.count {
if curlay[curlay.count-1-x] == dimen[curlay.count-1-x]-1 {
max = curlay.count-1-x
}
else {break}
}
if max == 0 {break}
else if max != -1 {
for n in max..<curlay.count {
curlay[n] = -1
}
curlay[max-1] += 1
}
curlay[curlay.count-1] += 1
print(curlay)
energy[curlay] = { () -> T in
switch with {
case ElectronInitializer.repeating(let value):
return value as! T
case ElectronInitializer.random(let minimum, let maximum):
return Double.random(in: minimum..<maximum) as! T
}
}()
}
}
And then of course, to change how you create it in your zero property
public static var zero: Electron<T> {
return Electron.init([], with: ElectronInitializer.repeating(0.0))
}
ElectronInitializer isn't actually used in this case. It's just a required parameter of your existing init. This suggests an opportunity to refactor initialization, so you could have an init() that creates a zero Electron in addition to your existing init(dim:with:)

Swift - Combine multiple discount types

so I've been playing around with protocol witness types, which are in essence concrete implementations of protocols. Say we have a protocol which discounts an item, returning a double.
Instead of this:
protocol Discountable {
func discount() -> Double
}
One does this:
struct Discounting<A> {
let discount: (A) -> Double
}
And, instead of conforming once a type to the Discountable protocol like this:
extension Double: Discountable {
func discount() -> Double {
return self * 0.9
}
}
One can offer multiple concrete implementations for a type:
extension Discounting where A == Double {
static let tenPercentOff = Self { amount in
amount * 0.9
}
static let fiveDollarsOff = Self { amount in
amount - 5
}
}
However, I was wondering how one could combine multiple of these discounts. Here's my initial sketch:
static func combine(_ discounts: [Discounting<A>]) -> Discounting<A> {
Discounting { (amount: A) -> Double in
return discounts.reduce(0.0) { current, discount in
// ??
}
}
}
However, I'm not sure what to put inside the reduce closure.
How can I combine multiple of these Discounting types into one?
With this design, you cannot compose a list of Discounting<A>s for an arbitrary A.
A Discounting<A> represents a way to compute the price after a discount, given an A object. Note that this is a function of A, not a function of price. From the linked article, this type parameter A seems to represent the thing to which you are discounting.
So basically, the information that a [Discounting<A>] contains is a list of functions that, given a thing A, can give you the discounted price for them. As you can see, there is no room for "applying another discount". All you get after applying the first discount is the discounted price, but Discounting represents discounts on things, not prices. You need a discounted A object to apply the second discount.
If you had a Discounting<Double> however, composition is possible,
func combine(_ discounts: [Discounting<Double>]) -> Discounting<Double> {
Discounting(discount: discounts.reduce({ $0 }, { compose($0, $1.discount) }))
}
func compose<T, U, V>(_ f1: #escaping (T) -> U, _ f2: #escaping (U) -> V) -> ((T) -> V) {
{ f2(f1($0)) }
}
To solve the problem for the general case, Discounting<A> could be redesigned as returning a discounted version of the input:
struct Discounting<A> {
let discount: (A) -> A
}
// This is the "protocol witness" version of:
//
// protocol Discountable {
// func discount() -> Self
// }
This way, you can also compose them with the same code that composes Discounting<Double>s that I showed above:
func combine<T>(_ discounts: [Discounting<T>]) -> Discounting<T> {
Discounting(discount: discounts.reduce({ $0 }, { compose($0, $1.discount) }))
}
Example usage:
struct Purchase {
var amount: Double
var shippingAmount: Double
}
extension Discounting where A == Purchase {
static let tenPercentOff: Self = .init { purchase in
Purchase(amount: purchase.amount * 0.9, shippingAmount: purchase.shippingAmount)
}
static let tenPercentOffShipping: Self = .init { purchase in
Purchase(amount: purchase.amount, shippingAmount: purchase.shippingAmount * 0.9)
}
static let fiveDollarsOff: Self = .init { purchase in
Purchase(amount: purchase.amount - 5, shippingAmount: purchase.shippingAmount)
}
}
let combinedDiscounts: Discounting<Purchase> = combine([.tenPercentOff, .fiveDollarsOff, .tenPercentOffShipping])
// Purchase(amount: 85.0, shippingAmount: 90.0)
print(combinedDiscounts.discount(Purchase(amount: 100, shippingAmount: 100)))

Can you simultaneously define and instantiate implicit types in Swift?

Just messing around with the language thinking of how I want to structure some UserDefaults that automatically generate keys based on the hierarchy. That got me wondering... Is it possible to simultaneously define, and instantiate a type, like this?
let myUserSettings = {
let formatting = {
var lastUsedFormat:String
}
}
let lastUsedFormat = myUserSettings.formatting.lastUsedFormat
Note: I can't use statics because I specifically need instancing so nested structs/classes with static members will not work for my case.
Here's the closest thing I could come up with, but I hate that I have to create initializers to set the members. I'm hoping for something a little less verbose.
class DefaultsScope {
init(_ userDefaults:UserDefaults){
self.userDefaults = userDefaults
}
let userDefaults:UserDefaults
func keyForSelf(property:String = #function) -> String {
return "\(String(reflecting: self)).\(property)"
}
}
let sharedDefaults = SharedDefaults(UserDefaults(suiteName: "A")!)
class SharedDefaults : DefaultsScope {
override init(_ userDefaults:UserDefaults){
formatting = Formatting(userDefaults)
misc = Misc(userDefaults)
super.init(userDefaults)
}
let formatting:Formatting
class Formatting:DefaultsScope {
let maxLastUsedFormats = 5
fileprivate(set) var lastUsedFormats:[String]{
get { return userDefaults.stringArray(forKey:keyForSelf()) ?? [] }
set { userDefaults.set(newValue, forKey:keyForSelf()) }
}
func appendFormat(_ format:String) -> [String] {
var updatedListOfFormats = Array<String>(lastUsedFormats.suffix(maxLastUsedFormats - 1))
updatedListOfFormats.append(format)
lastUsedFormats = updatedListOfFormats
return updatedListOfFormats
}
}
let misc:Misc
class Misc:DefaultsScope {
var someBool:Bool{
get { return userDefaults.bool(forKey:keyForSelf()) }
set { userDefaults.set(newValue, forKey:keyForSelf()) }
}
}
}
So is there a simpler way?
Disclaimer: this is, probably, just an abstract solution that should not be used in real life :)
enum x {
enum y {
static func success() {
print("Success")
}
}
}
x.y.success()
Update: Sorry, folks, I can't stop experimenting. This one looks pretty awful :)
let x2= [
"y2": [
"success": {
print("Success")
}
]
]
x2["y2"]?["success"]?()
Update 2: One more try, this time with tuples. And since tuples must have at least two values, I had to add some dummies in there. Also, tuples cannot have mutating functions.
let x3 = (
y3: (
success: {
print("Success")
},
failure: {
print("Failure")
}
),
z3: 0
)
x3.y3.success()
How about you try nesting some swift structs?
struct x {
struct y {
static func success() {
print("success")
}
}
}
x.y.success()
You cannot have that kind of structure but you cant access y from inside x, since y is only visible inside the scope of x and so is success inside the scope of y. There is no way that you can access them from outside
One other alternative is to have higher order function like so, which return closure which is callable.
let x = {
{
{
print("Success")
}
}
}
let y = x()
let success = y()
success()
or
x()()()
The real world usage of higher order function for userdefaults could be something like this,
typealias StringType = (String) -> ((String) -> Void)
typealias IntType = (String) -> ((Int) -> Void)
typealias BoolType = (String) -> ((Bool) -> Void)
typealias StringValue = (String) -> String?
typealias IntValue = (String) -> Int?
typealias BoolValue = (String) -> Bool?
func userDefaults<T>(_ defaults: UserDefaults) -> (String) -> ((T) -> Void) {
return { key in
return { value in
defaults.setValue(value, forKey: key)
}
}
}
func getDefaultsValue<T>(_ defaults: UserDefaults) -> (String) -> T? {
return { key in
return defaults.value(forKey: key) as? T
}
}
let setStringDefaults: StringType = userDefaults(.standard)
setStringDefaults("Name")("Jack Jones")
setStringDefaults("Address")("Australia")
let setIntDefaults: IntType = userDefaults(.standard)
setIntDefaults("Age")(35)
setIntDefaults("Salary")(2000)
let setBoolDefaults: BoolType = userDefaults(.standard)
setBoolDefaults("Married")(false)
setBoolDefaults("Employed")(true)
let getStringValue: StringValue = getDefaultsValue(.standard)
let name = getStringValue("Name")
let address = getStringValue("Address")
let getIntValue: IntValue = getDefaultsValue(.standard)
let age = getIntValue("Age")
let salary = getIntValue("Salary")
let getBoolValue: BoolValue = getDefaultsValue(.standard)
let married = getBoolValue("Married")
let employed = getBoolValue("Employed")
I am not sure if you like the pattern, but it has some good use cases as you can see from below, setStringDefaults you can set strings value to string key and all of them are typesafe.
You can extend this for your use case. But, you could use struct as well and use imperative code, which could be easier to understand. I see beauty in this as well.
Ok, I think I've figured it out. This first class can go in some common library that you use for all your apps.
class SettingsScopeBase {
private init(){}
static func getKey(setting:String = #function) -> String {
return "\(String(reflecting:self)).\(setting)"
}
}
The next part is a pair of classes:
The 'Scoping' class where you define which user defaults instance to use (along with anything else you may want to specify for this particular settings instance)
The actual hierarchy that defines your settings
Here's the first. I'm setting this up for my shared settings between my application and it's extension:
class SharedSettingsScope : SettingsScopeBase{
static let defaults = UserDefaults(suiteName: "group.com.myco.myappgroup")!
}
And finally, here's how you 'set up' your hierarchy as well as how you implement the properties' bodies.
class SharedSettings:SharedSettingsScope{
class Formatting:SharedSettingsScope{
static var groupsOnWhitespaceOnlyLines:Bool{
get { return defaults.bool(forKey: getKey()) }
set { defaults.set(newValue, forKey: getKey()) }
}
}
}
And here's how you use them...
let x = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// x = false
SharedSettings.Formatting.groupsOnWhitespaceOnlyLines = true
let y = SharedSettings.Formatting.groupsOnWhitespaceOnlyLines
// y = true
I'm going to see if I can refine/optimize it a little more, but this is pretty close to where I want to be. No hard-coded strings, keys defined by the hierarchy where they're used, and only setting the specific UserDefaults instance in one place.

`sum` extension on Measurement Sequence

Here's what I've currently got. It has at least these problems:
It crashes, when used on an array of Measurement<UnitType>, when
the units are mixed, such as with grams and milligrams.
Using an instance zero property isn't as good as a static alternative, which allows the return type to be the type's zero, instead of nil, for an empty sequence. I can't figure out if this is avoidable.
I use the first extension because Sequence.first doesn't exist in the current version of Swift. 🤔
import Foundation
public extension Sequence {
var first: Iterator.Element? {
return self.first{_ in true}
}
}
public extension Sequence where Iterator.Element: SummableUsingInstanceZero {
var sum: Iterator.Element? {
guard let zero = first?.zero
else {return nil}
return self.reduce(zero, +)
}
}
public protocol SummableUsingInstanceZero {
static func + (_: Self, _: Self) -> Self
var zero: Self {get}
}
extension Measurement: SummableUsingInstanceZero {
public var zero: Measurement {
return Measurement(
value: 0,
unit: unit
)
}
}
This question is old, but the solution is still not built-in. Conforming to AdditiveArithmetic is the way to go!
import Foundation
extension Measurement: AdditiveArithmetic where UnitType: Dimension {
public static var zero: Self {
Self( value: 0, unit: .baseUnit() )
}
public static func += (measurement0: inout Self, measurement1: Self) {
measurement0 = measurement0 + measurement1
}
public static func -= (measurement0: inout Self, measurement1: Self) {
measurement0 = measurement0 - measurement1
}
}