JetForMe
(Rick M)
1
Writing my first non-trivial Combine Publisher I found myself wanting to quickly get the min between a Subscribers.Demand and an Int. So I wrote this:
extension
Subscribers.Demand
{
static
func
min(_ inDemand: Self, _ inValue: Int)
-> Int
{
if inDemand == .unlimited
{
return inValue
}
return Swift.min(inDemand.max!, inValue)
}
}
So far, so good. But in my Publisher code, which looks like this:
extension
Publishers
{
final
class
Queueing<Upstream: Publisher>: Publisher
{
func
request(_ inDemand: Subscribers.Demand)
-> [Output]
{
let count = min(inDemand, self.queue.count)
^-- error here
let elements = Array(self.queue[..<count])
self.queue.removeFirst(count)
return elements
}
}
}
I get this error: Use of 'min' refers to instance method rather than global function 'min' in module 'Swift'. If I command-click min in Xcode, it goes nowhere, but there are a few min() methods in Combine.
Unfortunately, none of them take two arguments, and none matches the signature of my Subscriptions.Demand.min(Demand,Int) -> Int.
I don't think this is a bug, but it seems like something the compiler could unambiguously determine. Is this something I should report?
bzamayo
(Benjamin Mayo)
2
I don't think this is a bug, isn't your extension function min defined in the namespace of Subscribers.Demand and you are trying to use it — unqualified — in the namespace of Publishers.Queueing? So you'd have to write Subscribers.Demand.min(...) for it to know what you mean.
If you wrote your min as a free function outside of the extension, min(_:Subscribers.Demand, _:Int), then I think it should pick it up correctly.
2 Likes
BastianInuk
(Bastian Inuk Christensen)
3
A different approach is to remove the staticand inDemand and have it as
extension Subscribers.Demand
{
func min( _ inValue: Int) -> Int
{
if self == .unlimited
{
return inValue
}
return Swift.min(self.max!, inValue)
}
}
This would allow you to call it on any Subscribers.Demand as following:
extension Publishers
{
final class Queueing<Upstream: Publisher>: Publisher
{
func request(_ inDemand: Subscribers.Demand) -> [Output]
{
let count = inDemand.min(self.queue.count)
// ^-- new syntax here
let elements = Array(self.queue[..<count])
self.queue.removeFirst(count)
return elements
}
}
}
JetForMe
(Rick M)
4
That was, in fact, how I did it originally. But most uses of min are global function calls, and I thought perhaps I could treat it like binary operator definitions. But I guess not.
JetForMe
(Rick M)
5
Yeah, I guess I was thinking about how operators can be defined as static members. Maybe they're treated differently.
bzamayo
(Benjamin Mayo)
6
Yeah, the operator behaviour is special.
1 Like