The following code sample:
interface I<out T>
where T : class, I<T>
{
T GetT();
}
interface J : I<J>
{
}
abstract class B<T> : I<T>
where T : B<T>
{
T I<T>.GetT()
{
return null;
}
}
class C : B<C>, J
{
}
fails to compile (under VS2010 with SP1) with the following error:
Error 4 'C' does not implement interface member 'I<J>.GetT()'
However, C does implement (through its base B<C>) I<C>, which, due to I being declared covariant, should capture I<J> as well (as C : J).
Is this a compiler bug? If not, why am I not allowed to do that?
Even though it is covariant, you cannot change the return type of the interface. This is no different from the covariance in non-Generic classes.
interface Animal
{
Animal GetAnimal();
}
class Cat : Animal
{
//Not ALlowed
Cat GetAnimal()
{
return this;
}
//Allowed
Animal GetAnimal()
{
return this;
}
}
The problem is that C as a specialization of B<C> returns C I<C>.GetT(), however the specification of J requires J GetT().
Try the following:
interface I<out T>
where T : class, I<T>
{
T GetT();
}
interface J : I<J>
{
}
abstract class B<T,U> : I<U>
where T : B<T,U>, U
where U : class, I<U>
{
U I<U>.GetT()
{
return null;
}
}
class C : B<C,J>, J
{
}
Related
Is there a way to convert a string to an enum in vala:
string foo = "Enum1";
MY_ENUM theEnum = MY_ENUM.get_value_by_name(foo);
enum MY_ENUM {
Enum1,
Enum2,
Enum3
}
So in this example "theEnum" would have the value: MY_ENUM.Enum1
It is possible using the runtime type system provided by GLib's GObject library. There are EnumClass and EnumValue. These provide introspection at runtime and allow an enum to be initialised from a string.
The syntax is a bit complex at present, although it may be possible for someone to modify the Vala compiler to make it easier, but that is a significant piece of work.
An example:
void main () {
try {
MyEnum? the_enum_value;
the_enum_value = MyEnum.parse ("FIRST");
print (#"$(the_enum_value)\n");
} catch (EnumError error) {
print (#"$(error.message)\n");
}
}
errordomain EnumError {
UNKNOWN_VALUE
}
enum MyEnum {
FIRST,
SECOND,
THIRD;
public static MyEnum parse (string value) throws EnumError {
EnumValue? a;
a = ((EnumClass)typeof (MyEnum).class_ref ()).get_value_by_name ("MY_ENUM_" + value);
if (a == null) {
throw new EnumError.UNKNOWN_VALUE (#"String $(value) is not a valid value for $(typeof(MyEnum).name())");
}
return (MyEnum)a.value;
}
}
i don't know how to define the type of class's collection in typescript:
When i compile the following code, i've got an error:
class Wall{
brick: string;
constructor(){
this.brick = "jolies briques oranges";
}
// Wall methods ...
}
class Critter {
CritterProperty1: string[];
CritterProperty2: string;
constructor() {
this.CritterProperty1 = "n ne e se s so o no".split(" ");
}
// Critter methods ...
}
type legendObjectType = Critter | Wall;
interface Ilegend {
[k: string]: legendObjectType;
}
// i've got an issue to define the type of 'theLegend' Object
let theLegend: Ilegend = {
"X": Wall,
"o": Critter
}
error TS2322: Type '{ "X": typeof Wall; "o": typeof Critter; }' is not
assignable to type 'Ilegend'.
while i can compile it, if the "Class Wall" is empty.
does anyone know how to define the type of such a class's collection?
let theLegend = {
"X": Wall,
"o": Critter }
(this is an exemple from the chapter 7 of eloquent javascript, than i try to transcribe in typescript)
EDIT
i complete the Rico Kahler's answer, with an abstract Class to avoid using the union type
abstract class MapItem {
originChar: string;
constructor(){}
}
class Wall extends MapItem {
brick: string;
constructor(){
super();
this.brick = "jolies briques oranges";
}
// Wall methods ...
}
class Critter extends MapItem {
CritterProperty1: string[];
CritterProperty2: string;
constructor() {
super();
this.CritterProperty1 = "n ne e se s so o no".split(" ");
}
// Critter methods ...
}
interface Ilegend {
[k: string]: new () => MapItem;
}
let theLegend: Ilegend = {
"X": Wall,
"o": Critter
}
thank's.
Your issue lies your object theLegend.
Typescript is expect an instance of Wall or Critter but instead you're providing it with a type.
let theLegend: Ilegend = {
"X": Wall, // `Wall` is a type not an instance, it is `typeof Wall` or the Wall type
"o": Critter // `Criter` is a type not an instance
}
Something like the following will work:
let theLegend: Ilegend = {
X: new Wall(), // now it's an instance!
o: new Critter()
}
Edit:
Now reading the javascript pages you linked, it seems like I missed your intent. If you want to create an interface that takes a constructor, then I would type Ilegend as follows:
interface Legend {
[k: string]: new () => (Critter | Wall)
}
// now you can define an object with this type
let legend: Legend = {
// here `Critter` actually refers to the class constructor
// that conforms to the type `new () => (Critter | Wall)` instead of just a type
something: Critter,
somethingElse: Wall
}
const critter = new legend.something() // creates a `Critter`
const wall = new legend.somethingElse() // creates a `Wall`
// however, the type of `critter` and `wall` are both `Critter | Wall`. You'd have to use type assertion (i.e. casting) because typescript can't tell if its either a Critter or a Wall
Now the interfaces allows any string to be a key and it expects every value to be a function that you can call new on to get either a Critter or a Wall
I have a simple Object hierarchy : RESTError with 2 attributes (httpCode and message), and 4 subclasses of it. One of the subclasses, RESTBusinessError has two additional fields.
I've simplified my code here below, but a RESTError variable (which is actually a RESTBusinessError) is used within a switch statement. Whenever I try to access the fields of the subclass, I've a EXC_BAD_ACCESS. Any idea ? this looks obvious, and in the debug area, I can see that all my variables have the expected values.
I have this issue ONLY in case RESTError conforms to the protocol ErrorType.
Any Idea ?
var tmpError:RESTError;
tmpError=RESTBusinessError(httpCode: 422, message: "error", businessCode: "003", businessMessage: "error");
switch tmpError {
case is RESTAuthorisationError:print("AUTH Error");
case let bError as RESTBusinessError:
let s1=bError.httpCode;
let s2=bError.message;
let s3=bError.businessCode; // <- This systematically fails.
let s4=bError.businessMessage;
print("OK \(s1) \(s2) \(s3) \(s4)");
default: print("default");
}
Object Hierarchy is here below :
public class RESTError : ErrorType{
var httpCode:Int
var message:String
init(httpCode:Int,message:String) {
self.httpCode=httpCode;
self.message=message;
}
}
class RESTAuthorisationError : RESTError {}
class RESTServerError : RESTError {}
class RESTOtherError : RESTError {}
public class RESTBusinessError : RESTError {
var businessCode:String
var businessMessage:String
init(httpCode:Int,message:String, businessCode:String, businessMessage:String) {
self.businessCode=businessCode;
self.businessMessage=businessMessage;
super.init(httpCode: httpCode, message: message);
}
}
check this example
import Foundation
func f() {
let queue = dispatch_queue_create("a", DISPATCH_QUEUE_CONCURRENT)
var i: Int! = 0
dispatch_async(queue) {
i = nil
}
usleep(200000)
print(i) // this is wrong
}
f() // debugger will stop here !!!!
In Objective-C, I know how passing a protocol as parameter:
- (void)MyMethod:(Protocol *)myparameter
But in Swift there is no more Protocol type.
How can I pass a protocol as parameter without knowing which is ?
In one of your comments you say:
"I want create a method which return an array of type of class which implements a desired protocol."
Have you tried something like the following:
//notice the use of #objc here
#objc protocol AlertProtocol
{
func getMyName()->String
}
class Class1 : AlertProtocol
{
let name = "Object 1"
func getMyName() -> String
{
return name
}
}
class Class2 : AlertProtocol
{
let name = "Object 2"
func getMyName() -> String
{
return name
}
}
//borrowing from and refactoring siLo's answer
func classesConformingToProtocol(proto:Protocol) -> [AnyClass]
{
let availableClasses : [AnyClass] = [ Class1.self, Class2.self ]
var conformingClasses = Array<AnyClass>()
for myClass : AnyClass in availableClasses
{
if myClass.conforms(to: proto)
{
conformingClasses.append(myClass)
}
}
return conformingClasses
}
Then use the above structure like this:
let classes = classesConformingToProtocol(AlertProtocol.self)
The tricky part that does the work is the "#objc" that exposes the protocol to the objective c runtime and allows us to pass any "Protocol Type" as a parameter.
Probably at some point in the future we will be able to do this in a "pure" Swift way.
Here is what I have tried:
#objc protocol Walker
{
func walk()
}
#objc protocol Runner
{
func run()
}
#objc class Zombie : Walker
{
func walk () { println("Brains...") }
}
#objc class Survivor : Runner
{
func run() { println("Aaaah, zombies!") }
}
func classesConformingToProtocol(proto:Protocol) -> AnyClass[]
{
let availableClasses : AnyClass[] = [ Zombie.self, Survivor.self ]
var conformingClasses = Array<AnyClass>()
for myClass : AnyClass in availableClasses
{
if myClass.conformsToProtocol(proto)
{
conformingClasses.append(myClass)
}
}
return conformingClasses
}
// This does not work
let walkers = classesConformingToProtocol(Walker.self)
let runners = classesConformingToProtocol(Runner.self)
I have been unable to convert Swift's Metatype information into a Protocol object.
In swift 2.0, I use it like this before:
classA.conformsToProtocol(XXXProtocol.self as! Protocol)
It doesn't works fine...
Look the definition of Protocol:
// All methods of class Protocol are unavailable.
// Use the functions in objc/runtime.h instead.
#available(iOS 2.0, *)
public class Protocol {
}
All are unavailable...and I don't know which to use instead in objc/runtime.h
So I have to use this method:
if ClassA is protocol<XXXProtocol> {
// do something
}
Currently, it works...
If you don't allow use #objc (because yours protocols have property, for example), the only solution that I found is with closure. Then, you need use a closure to use a protocol and return a value.
protocol Proto { }
protocol Proto2 { }
class Foo: Proto { }
class Bar: Proto, Proto2 { }
class Baz: Proto2 { }
class Qux { }
func printConforms(classList: [AnyClass], protoCond: (AnyClass) -> Any?) {
for i in classList {
print(i, terminator: " -> ")
if protoCond(i) != nil {
print("is subscriber")
} else {
print("NOT IS subscriber")
}
}
}
let myClasses: [AnyClass] = [Foo.self, Bar.self, Baz.self, Qux.self]
printConforms(classList: myClasses, protoCond: { $0 as? Proto.Type })
More complete example: https://gist.github.com/brunomacabeusbr/eea343bb9119b96eed3393e41dcda0c9
Edit
Another better solution is using generics, for example:
protocol Proto { }
class Foo: Proto { }
class Bar: Proto { }
class Baz { }
func filter<T>(classes: [AnyClass], byConformanceTo: T.Type) -> [AnyClass] {
return classes.filter { $0 is T }
}
filter(classes: [Foo.self, Bar.self, Baz.self], byConformanceTo: Proto.Type.self)
// return [Foo.self, Bar.self]
Worked out a way today (Xcode 6.1):
Firstly, the protocol must be marked as #objc for any checking to work.
Then use an "if let" cast to check for conformance.
#objc protocol MyProtocol {
var protocolValue: Int { get set }
}
if let conformingObject = someObject as? MyProtocol {
// conformingObject is now someObject cast to MyProtocol
conformingObject.protocolValue = 3
}
Why does the following
class Test {
#Test
void go() {
def foo1 = new MockFoo1() as Foo
def foo2 = new MockFoo2() as Foo
}
interface Foo {}
class MockFoo1 {}
class MockFoo2 {}
}
Result in a java.lang.IllegalArgumentException: argument type mismatch on the foo2 coercion?
This only happens if I coerce 2 objects of 2 different types to the same interface during a single path of execution. The groovy approved way of using closures or maps to achieve this kind of duck typing works fine.
Any light shed appreciated.
It's a bug with the ProxyGenerator adapterCache. As a workaround, you can also use some Groovy trickery to make this work:
interface Foo {
static a = {
[MockFoo1, MockFoo2].each {
it.metaClass.asType = { Class klazz ->
try {
DefaultGroovyMethods.asType(delegate, klazz)
} catch (e) {
def cache = ProxyGenerator.INSTANCE.#adapterCache.#cache
cache.each { k, v ->
cache.remove(k)
}
DefaultGroovyMethods.asType(delegate, klazz)
}
}
}
}()
}
class MockFoo1 {}
class MockFoo2 {}
def a = new MockFoo1() as Foo
def b = new MockFoo2() as Foo
assert a instanceof Foo
assert b instanceof Foo
Hope this helps!