Consider the following interface definitions:
[
//...
dual,
//...
]
interface IFoo : IDispatch{
}
[
//...
dual,
//...
]
interface IBar : IDispatch{
[propput, id(1)] HRESULT foo([in] IFoo* newVal);
};
I'm working with an object implementing IBar in JScript:
myBar.foo = someFoo; // so far so good
How can I set foo to null?
myBar.foo = null; // "Type mismatch"
myBar.foo = 0; // "Type mismatch"
The answer is: it's impossible.
Related
I have a companion object with a named object inside of it, but unless I use Companion. kotlin can't resolve the reference
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
If I switch to val Obj = object { ... } then neither access works if I try to reference attr, but both allow me to reference Obj
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
I don't understand this behavior. What's going on? My only guesses would be around static initialization ordering problems.
First, Answering the second question.
class Cls {
companion object {
val Obj = object {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
}
Here the object{} is called as anonymous object which is assigned to the variable as val object It does not have any references.
When you check here, Cls.Obj is of type Any.
So you cannot access like Any.attr because Any is root of all Kotlin class, it will only have default fucntions like hashcode(), equals()...
Since it is an anonymous object, you cannot do type cast.So no way to access attr directly.
To access attr , you can acheive with interface.
interface Foo{
fun attrs():Int
}
class Cls {
companion object {
val Obj = object : Foo{
var attr = 1
override fun attrs(): Int = attr
}
}
}
fun main() {
println(Cls.Obj.attrs()) // Print attr value 1
}
Here is the compiled code looks like of this.
public final class Cls public constructor() {
public companion object {
public final val Obj: kotlin.Any /* compiled code */
}
}
When you see here, Obj is a variable inside which is of type Any.
In Kotlin, you can access variables inside companion object in both ways with or without Companion. Both will work.
println(Cls.Obj) // ok
println(Cls.Companion.Obj) // ok
In java , we need to access like,
Cls.Companion.getObj().
In Kotlin ,Companion word can be ignored. So accessing variables in companion object is the better one without using companion,like below.
println(Cls.Obj) // ok
Coming to First Question
class Cls {
companion object {
object Obj {
val attr = 1
}
}
}
fun main() {
println(Cls.Obj.attr) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj.attr) // ok
println(Cls.Obj) // Error: "Unresolved reference: Obj"
println(Cls.Companion.Obj) // ok
}
Here you use object inside companion object, which is a nested object. This is similar to Nested static class in java, but not the same.
public final class Cls public constructor() {
public companion object {
public object Obj {
public final val attr: kotlin.Int /* compiled code */
}
}
}
The above one is the compiled code of the first one. When you check here, you have object inside companion object. But in your second question, you have made that Obj as variable. So you can directly call that variable. But here since it is a nested object, you should use companion keyword to access Obj.
Cls.Companion.Obj is the valid one.
When you access Obj like this Cls.Obj, the compiler checks for variable named 'Obj' inside that companion object. But there is no such variable because its an nested object.
And to make it clear,here is another example.
class Cls {
companion object {
object Obj {
val attr = 1
}
object Obj1{
val attr = 2
}
}
}
Hope it helps you.
I´m using AWS Cognito, in the doc it says I have to add this function.
But I´m getting this error:
Extension of a generic Objective-C class cannot access the class's generic parameters at runtime
extension AWSTask {
public func continueWithExceptionCheckingBlock(completionBlock:#escaping (_ result: Any?, _ error: Error?) -> Void) {
self.continue({(task: AWSTask) -> Any? in
if let exception = task.exception {
print("Fatal exception: \(exception)")
kill(getpid(), SIGKILL);
}
let result: AnyObject? = task.result
let error: NSError? = task.error as NSError?
completionBlock(result, error)
return nil
})
}
}
For those who have this issue in Swift 5, try adding #objc modifier to the method. Please find the example below:
extension NSLayoutAnchor {
#objc func constrainEqual(_ anchor: NSLayoutAnchor<AnchorType>, constant: CGFloat = 0) {
let constraint = self.constraint(equalTo: anchor, constant: constant)
constraint.isActive = true
}
}
Without context I can't say if you are actually doing what the error message prompts you with, but there is an open bug report describing this issue (where no offending code is actually used):
SR-2708: Extending ObjC generics in Swift 3 does not compile
ObjC:
#interface MySet<T : id<NSCopying>> : NSObject
#end
Swift:
class Foo { }
struct Bar { }
extension MySet {
func foo() -> Foo { return Foo() }
func bar() -> Bar { return Bar() }
}
Both of the extension methods result in "Extension of a generic Objective-C class cannot access the class's generic parameters at
runtime". However, neither really does anything like that (at least
not explicitly).
If you read the comments to the bug report, you'll see that a user named 'Vasili Silin' describes having this issue when attempting to extend AWSTask, so you might have to consider alternative approaches until this bug is resolved.
I just got the same error and solve it this way :
extension yourClass where T == yourType {}
MMCondition is a protocol defined in Swift, but interoperates with Objective-C (annotated with #objc).
#objc public protocol MMCondition {
static var name: String { get }
static var isMutuallyExclusive: Bool { get }
}
I have the following code:
// addCondition cannot be generic as I want it to be accessible from Objective-C as well.
public func addCondition(condition: MMCondition) {
// How do I initialize OperationConditionImplementer here?
let operationCondition = OperationConditionImplementer(condition: condition) // doesn't compile
// Error: Cannot invoke initializer for type 'OperationConditionImplementer<T>' with an argument list of type '(condition: MMCondition)'
// Can I use condition.dynamicType to init OperationConditionImplementer somehow?
}
struct OperationConditionImplementer<T: MMCondition> {
let condition: T
static var name: String {
return "Silent<\(T.name)>"
}
static var isMutuallyExclusive: Bool {
return T.isMutuallyExclusive
}
init(condition: T) {
self.condition = condition
}
}
From Objective-C, you can't use generics as stated in the documentation.
You’ll have access to anything within a class or protocol that’s
marked with the #objc attribute as long as it’s compatible with
Objective-C. This excludes Swift-only features such as those listed
here:
Generics
...
So you need to remove completely the generics code. One possible solution might be:
#objc protocol MMCondition {
static var name: String { get }
static var isMutuallyExclusive: Bool { get }
}
struct OperationConditionImplementer {
let condition: MMCondition
var name: String {
return "Silent<\(condition.dynamicType.name)>"
}
var isMutuallyExclusive: Bool {
return condition.dynamicType.isMutuallyExclusive
}
init(condition: MMCondition) {
self.condition = condition
// Here decide comparing types
if condition.dynamicType === ExampleCondition.self {
print(condition.dynamicType.name)
}
}
}
So for instance, if you try it out in a playground:
class ExampleCondition: NSObject, MMCondition {
static var name: String = "ExampleCondition"
static var isMutuallyExclusive: Bool = false
}
let example = OperationConditionImplementer(condition: ExampleCondition())
You'll see "ExampleCondition" printed.
If you eventually switch to pure Swift, you need to specify T when initializing a OperationConditionImplementer.
You can achieve that defining the addCondition method as:
func addCondition<T: MMCondition>(condition: T) {
let a = OperationConditionImplementer<T>(condition: condition)
}
Since Swift 2.0 instances of generic classes can implement Objective-C protocols. What won't be possible I believe is having a struct implement the protocol. In fact I expect that your protocol may need to inherit from NSObjectProtocol to be usable in Objective-C which would then prevent you from implementing the protocol with structs or enums.
You also rightly mention that you can't access generic functions from Objective-C.
For a concrete example of using a generic to fulfil an Objective-C protocol have a look at this blog post.
We have a typical getter in one of our classes, lets say
class Employee implements IEmployee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
}
and an interface to work with it
interface IEmployee{
fullName: string;
}
When working with an instance via this interface the compiler will not warn us about absence of a setter if we try to assign to fullName, and the the JS runtime simply swallows any assignment and does not throw an error. Is there any way to mark interface member as having only getter or only setter?
I've seen this post, but it is quite old, i want to know, if anything improved.
Properties in typescript can now have 'readonly' modifier, which achieves the desired restult.
interface IEmployee{
readonly fullName: string;
}
This is an interesting question. The concept of a readonly property is subtly different in TypeScript to other languages.
In many languages a property with a getter (but no setter) would raise a compiler error if you attempted to set the property, but TypeScript doesn't.
The property is still readonly, because it makes no difference if you attempt to set it; the set will fail silently.
Here is an example without any interfaces:
class Example {
get name() {
return 'Steve';
}
}
var y = new Example();
y.name = 'Example 2';
alert(y.name);
There is no compiler warning when I use x.name = 'Example 2';.
If there was a compiler warning, I would subsequently expect there to be a way of specifying the readonly-ness of a property within an interface. As you'd expect though, given the above information, you can't set a readonly property on an interface.
interface Test {
name: string;
}
class Example {
get name() {
return 'Steve';
}
}
var x: Test = new Example();
x.name = 'Example 1';
alert(x.name);
var y = new Example();
x.name = 'Example 2';
alert(x.name);
This means you can only enforce readonly-ness by having a method to get the value of the property (and obviously no method that allows it to be set).
interface Test {
getName: () => string;
}
class Example {
getName() {
return 'Steve';
}
}
var x: Test = new Example();
//x.getName('Obviously not');
//x.getName() = 'Obviously not';
alert(x.getName());
var y = new Example();
//y.getName('Obviously not');
//y.getName() = 'Obviously not';
alert(y.getName());
My level of typescript is 'ABSOLUTE BEGINNER' but I have a good OOP background. I am building an with typescript that reference an external t.ds library that contains the following interface:
interface ISimpleObject {
foo: string;
bar?: any;
}
Now, if I want to call a method that has an IRequestConfig parameter, how do I create one? I can see different options:
Create a simple implementation of ISimpleObject. I don't like this approach because it looks like boilerplate code to me
don't initialize the object (I fear this could break something...):
var x :IsimpleObject;
x.bar = 'xxx';
callMethod(x);
Cast a pojo:
var x :IsimpleObject = <IsimpleObject>{foo: 'yyy', bar:'xxx'};
I don't like this approach either because it doesn't enforce type safety...
I guess this is a fairly trivial question and I am missing something trivial about typescript.
Typescript2:
const simpleObject = {} as ISimpleObject;
If you have an interface like:
interface ISimpleObject {
foo: string;
bar?: any;
}
This interface is only used at compile time and for code-hinting/intellisense. Interfaces are used to provide a rigorous and type-safe way of using an object with a defined signature in a consistent manner.
If you have a function using the interface defined above:
function start(config: ISimpleObject):void {
}
The TypeScript compile will fail if an object does not have the exact signature of the ISimpleObject interface.
There are multiple valid techniques for calling the function start:
// matches the interface as there is a foo property
start({foo: 'hello'});
// Type assertion -- intellisense will "know" that this is an ISimpleObject
// but it's not necessary as shown above to assert the type
var x = <ISimpleObject> { foo: 'hello' };
start(x);
// the type was inferred by declaration of variable type
var x : ISimpleObject = { foo: 'hello' };
start(x);
// the signature matches ... intellisense won't treat the variable x
// as anything but an object with a property of foo.
var x = { foo: 'hello' };
start(x);
// and a class option:
class Simple implements ISimpleObject {
constructor (public foo: string, public bar?: any) {
// automatically creates properties for foo and bar
}
}
start(new Simple("hello"));
Any time the signature doesn't match, the compile will fail:
// compile fail
var bad = { foobar: 'bad' };
start( bad );
// compile fail
var bad: ISimpleObject = { foobar: 'bad' };
// and so on.
There is no "right" way to do it. It's a matter of style choice. If it were an object that was constructed (rather than just directly passed as a parameter), I'd normally declare the type:
var config: ISimpleObject = { foo: 'hello' };
That way code-completion/IntelliSense will work anywhere I used the config variable:
config.bar = { extra: '2014' };
There is no "casting" in TypeScript. It is called a type assertion and shouldn't be needed in the cases described here (I included an example above where it could be used). There's no need to declare the variable Type and then use an assertion in this case (as the type was already known).
You can't create an instance of an interface since Typescript doesn't "translate" it into js. You can check the js that is created and you will see nothing in it. It's simple for compile errors, type safety and intelisense.
interface IStackOverFlow
{
prop1 : string;
prop2 : number;
}
public MyFunc(obj : IStackOverFlow)
{
// do stuff
}
var obj = {prop1: 'str', prop2: 3};
MyFunc(obj); // ok
var obj2 = {prop1: 'str'};
MyFunc(obj); // error, you are missing prop2
// getObj returns a "any" type but you can cast it to IStackOverFlow.
// This is just an example.
var obj = <IStackOverFlow> getObj();