Add constraints to generic parameters in extension
Try this code in the Playground:
// make sure only `Optional` conforms to this protocol
protocol OptionalEquivalent {
typealias WrappedValueType
func toOptional() -> WrappedValueType?
}
extension Optional: OptionalEquivalent {
typealias WrappedValueType = Wrapped
// just to cast `Optional<Wrapped>` to `Wrapped?`
func toOptional() -> WrappedValueType? {
return self
}
}
extension Dictionary where Value: OptionalEquivalent {
func flatten() -> Dictionary<Key, Value.WrappedValueType> {
var result = Dictionary<Key, Value.WrappedValueType>()
for (key, value) in self {
guard let value = value.toOptional() else { continue }
result[key] = value
}
return result
}
}
let a: [String: String?] = ["a": "a", "b": nil, "c": "c", "d": nil]
a.flatten() //["a": "a", "c": "c"]
Because you cannot specify an exact type in the where
clause of a protocol extension, one way you may detect exactly the Optional
type is to make Optional
UNIQUELY conforms to a protocol (say OptionalEquivalent
).
In order to get the wrapped value type of the Optional
, I defined a typealias WrappedValueType
in the custom protocol OptionalEquivalent
and then made an extension of Optional, assgin the Wrapped
to WrappedValueType
, then you can get the type in the flatten method.
Note that the sugarCast
method is just to cast the Optional<Wrapped>
to Wrapped?
(which is exactly the same thing), to enable the usage guard
statement.
UPDATE
Thanks to Rob Napier 's comment I have simplified & renamed the sugarCast() method and renamed the protocol to make it more understandable.
How do I write an extension method for a generic type with constraints on type parameters?
You need to add the same type parameter constraints on the extension method.
This is my attempt at the closest reconstruction of your example that compiles and runs, without any error:
public class Matrix<T> where T : new() {
public T[,] values;
}
public static class MatrixExtension {
public static T getCalcResult<T>(this Matrix<T> mat) where T : new() {
T result = new T();
return result;
}
}
class Program {
static void Main(string[] args) {
Matrix<int> m = new Matrix<int>();
int aNumber = m.getCalcResult();
Console.WriteLine(aNumber); //outputs "0"
}
c# extension method for a generic class with interface as type constraint
Yes, this can be done by making the method generic and adding a generic type constraint to the method, as follows:
public static void SomeMethod<T>(
this SomeClass<T> obj, ISomeInterface objParam)
where T : ISomeInterface // <-- generic type constraint
{
...
}
Is it possible to add type constraints to a Swift protocol conformance extension?
EDIT: As noted in the updated question, this is now possible since Swift 4.1
This is not currently possible in Swift (as of Xcode 7.1). As the error indicates, you can't restrict protocol conformance ("inheritance clause") to a type-constrained extension. Maybe someday. I don't believe there's any deep reason for this to be impossible, but it's currently not implemented.
The closest you can get is to create a wrapper type such as:
struct FriendlyArray<Element: Friendly>: Friendly {
let array: [Element]
init(_ array: [Element]) {
self.array = array
}
func sayHi() {
for elem in array {
elem.sayHi()
}
}
}
let friendly: Friendly = FriendlyArray(["Foo", "Bar"])
(You would likely want to extend FriendlyArray
to be a CollectionType
.)
For a tale of my own descent into the madness of trying to make this work, and my crawl back from the edge, see NSData, My Old Friend.
Nested Generic Constraints: Constrain the T of a generic item inside a generic sequence extension that is constrained to that generic type
You can restrict Iterator.Element
to types conforming toObservableType
and then add another constraint for the associated type E
of Iterator.Element
:
protocol ObservableType {
associatedtype E
// ...
}
class MyType { }
extension Sequence where Iterator.Element: ObservableType, Iterator.Element.E: MyType {
}
Extension methods for specific generic types
This isn't possible in the current version of F#, unfortunately. See related question here.
Creating an extension method against a generic interface or as a generic constraint?
Yes there is.
The first signature would match any type that can be compared to T
, not just T
values. So any type that implements IComparable<int>
can be used by the first signature, not just int
.
Example:
void Main()
{
10.IsFoo(20).Dump();
new Dummy().IsFoo(20).Dump();
IComparable<int> x = 10;
x.IsFoo(20).Dump();
IComparable<int> y = new Dummy();
y.IsFoo(20).Dump();
}
public class Dummy : IComparable<int>
{
public int CompareTo(int other)
{
return 0;
}
}
public static class Extensions
{
public static bool IsFoo<T>(this IComparable<T> value, T other)
where T : IComparable<T>
{
Debug.WriteLine("1");
return false;
}
public static bool IsFoo<T>(this T value, T other)
where T : IComparable<T>
{
Debug.WriteLine("2");
return false;
}
}
Will output:
2
False
1
False
1
False
1
False
I tested this with LINQPad.
How do I constrain a Kotlin extension function parameter to be the same as the extended type?
As mentioned by @Alexander Udalov it's not possible to do directly but there's a workaround where you define the extension method on another type like so:
data class Wrapper<T>(val value: T)
val <T> T.ext: Wrapper<T> get() = Wrapper(this)
fun <T> Wrapper<T>.thing(p: T) {
println("value = $value, param = $p")
}
With the above the following compiles:
"abc".ext.thing("A")
but the next fails
"abc".ext.thing(2)
with:
Kotlin: Type inference failed: Cannot infer type parameter T in fun <T> Wrapper<T>.thing(p: T): Unit
None of the following substitutions
receiver: Wrapper<String> arguments: (String)
receiver: Wrapper<Int> arguments: (Int)
can be applied to
receiver: Wrapper<String> arguments: (Int)
As suggested by @hotkey it seems that it should be possible to avoid the need for explicit Wrapper
type with the following extension property:
val <T> T.thing: (T) -> Any? get() = { println("extension body") }
And then use it as "abc".thing("A")
but it also fails. Surprisingly the following does compile "abc".thing.invoke("A")
Related Topics
How to Demonstrate a Zombie Object in Swift
Swift: When Should I Use "Var" Instead of "Let"
Cannot Invoke 'Filter' with an Argument List of Type '((_) -> _)'
Many Ways of Defining a Swift Dictionary
Get Bogus Value When Execute Break Point in a Variable
Expand and Contract Tableview Cell When Tapped, in Swift
iOS - Add Image and Text in Title of Navigation Bar
Read and Write Permission for User Selected Folder in MAC Os App
Swiftui - in Sheet Have a Fixed Continue Button That Is Not Scrollable
Why Does Int(Float(Int.Max)) Give Me an Error
Gcd with Static Functions of a Struct
Define a Swift Protocol Which Requires a Specific Type of Sequence
Pattern Match and Conditionally Bind in a Single Switch Statement
Label Disappear When Changing Font Size to 25 in Swift