Allow default parameter in generic class definition
Several days ago I wrote a post about default parameters in generic class definition. It is not possible yet, but some techniques could emulate this behavior.
Simple task: implement priority queue from c++ stl.
Let's look at priority_queue from Cplusplus STL.
template <class T, class `Container` = vector<T>,
class Compare = less<typename Container::value_type> > class priority_queue;
It has three template parameters:
- Type of element T.
- Container type with elements matched Type T.
- Compare - binary function which will order elements in priority queue.
So, here we have three parameters, some of them could be omitted in case of default assumptions how this was done in c++ stl.
Default container value is vector<T>
.
Default compare class is less
with elements from container type.
I will try to implement similar functionality for priority queue in swift.
First, a definition of protocol and built-in comparison functions.
protocol BinaryCompareFunction {
associatedtype T
static func compare(lhs: T, rhs: T) -> Bool
}
struct BinaryCompareFunctions {
struct Less<E>: BinaryCompareFunction where E: Comparable {
typealias T = E
static func compare(lhs: E, rhs: E) -> Bool {
return lhs < rhs
}
}
}
Next, a definition of priority queue with several parameters ( Element parameter omitted in case of simplicity ).
// MARK: Definition
struct PriorityQueues {
class PriorityQueue<Container: Collection, Comparison: BinaryCompareFunction> where Container.Element == Comparison.T {
typealias Element = Container.Element
typealias ComparisonFunction = Comparison
var container: Container?
init(container: Container?) {
self.container = container
}
}
struct test {
}
}
There are several possible alternatives to specify generics parameters that I know:
- Naive
- Class method
- Subclass
- Class object
Naive
// MARK: Naive
extension PriorityQueues.test {
static func naive() {
let _ = PriorityQueues.PriorityQueue<Array<Int>, BinaryCompareFunctions.Less<Int>>(container: [])
}
}
Class method
// MARK: Class method
extension PriorityQueues.PriorityQueue {
class func defaultQueue<T: Comparable>(t: T) -> PriorityQueues.PriorityQueue<Array<T>, BinaryCompareFunctions.Less<T>> {
return PriorityQueues.PriorityQueue<Array<T>, BinaryCompareFunctions.Less<T>>(container: [])
}
}
extension PriorityQueues.test {
static func classMethod() {
let i: Int = 0
let _ = PriorityQueues.PriorityQueue<Array<Int>, BinaryCompareFunctions.Less<Int>>.defaultQueue(t: i)
}
}
Subclass
// MARK: Subclass
extension PriorityQueues {
class PriorityQueue_DefaultLess<T: Comparable>: PriorityQueue<Array<T>, BinaryCompareFunctions.Less<T>> {
convenience init() {
self.init(container: [])
}
}
}
extension PriorityQueues.test {
static func subclass() {
let _ = PriorityQueues.PriorityQueue_DefaultLess<Int>()
}
}
extension PriorityQueues.test {
static func easy() {
let _ = PriorityQueues.PriorityQueue_DefaultLess(container: [0])
}
}
Class object
Object companion if I remember. Similar item in Scala.
// MARK: Class Object
extension PriorityQueues {
class PriorityQueueObject<T: Comparable> {
class func defaultQueue() -> PriorityQueue<Array<T>, BinaryCompareFunctions.Less<T>> {
return PriorityQueue<Array<T>, BinaryCompareFunctions.Less<T>>(container: [])
}
}
}
extension PriorityQueues.test {
static func classObject() {
let _ = PriorityQueues.PriorityQueueObject<Int>.defaultQueue()
}
}
Most of them are clumsy.
It would be nice to have a mechanism similar to templates of c++ or Scala ( which makes it possible to set default type parameter in generics clauses ).