Method signature in Objective-C - ios

I'm trying to understand, how does method signature in Objective-C is look like.
INTRO:
At first, lets break misunderstandings about question, what is it, method signature?
Method signature it is something, that helps compiler unambiguously identifies subroutine.
Am i right? :)
So in the C language signature is roughly equivalent to its prototype definition:
For example, we have function int printf( const char *format, ... ); in stdlib.
Signature of this function is printf.
In this case, we can't overload in C language, because compiler can't identify function with different argument types, so people decide to do some tricky thing like this:
long int labs (long int n);
int abs (int n);
double fabs (double x);
In the C++ language, method signature is class name, method name and method arguments.
So in this language we can overload methods.
PROBLEM
I can't get simple answer, what is method signature in Objective-C?!
I'm trying to use my logic...
1)At first, we can't overloading in Objective-C => method arguments is not part of method signature.
2)I tried to compile code with different return value:
#interface Foo : NSObject
- (CGFloat)method;
- (NSInteger)method;
#end
I got error in this case => return value is not part of method signature.
I tested different cases and got the answer, method signature in Objective-C is class name, method type ('+' or '-') and selector.
For example, we have method in class Foo (code below):
#interface Foo : NSObject
+ (void)methodWithArgument:(NSInteger)argument;
#end
So the signature of this method is +[Foo methodWithArgument:]
But then, i look at apple's documentation of NSMethodSignature (http://bit.ly/1tGR8zt)
An NSMethodSignature object records type information for the arguments
and return value of a method
Arguments and return value?! Only using arguments and return value, we can unambiguously identify method? It's very strange.

First thing. Who said that compiler can differentiate between 2 methods on the basis or its return type
so
#interface Foo : NSObject
- (CGFloat)method;
- (NSInteger)method;
#end
is wrong. Even in C or C++ you cannot overload method on the basis of its return type. Overloading can be performed on the basis of type of argument or number of arguments for a methods or both.
so over loading can be performed in this way only
#interface Foo : NSObject
-(ReturnType)methodNameHere:(int)argument;
-(ReturnType)methodNameHere:(int)argument secondArgumentDescription:(BOOL)anotherArgument;
-(ReturnType)methodNameHere;
compiler identifies different methods on the basis for number of arguments and their data type

Method signature is for developers and for runtime,
Not for compiler. (Compiler uses another technique to understand signatures)

you cannot identify methods that have the same name but different return types. If you call it while discarding the return value, which one should be called?
#interface Foo : NSObject
- (CGFloat)method;
- (NSInteger)method;
#end
Foo *foo = [Foo new];
[foo method]; // no use for return value here. Which implementation to call?

Related

Is there a neater way to map member functions in dart?

Dart has a handy map function on iterables, and it accepts a lambda. So I can write something like:
// Stupid example class
class Foo {
int v;
int v2() { return v*v; }
}
List<int> mapFoos(List<Foo> foos) {
return foos.map( (Foo f) => f.v2() );
}
But this feels a little clunky to me. I'm used to being able to tell map to use the member function directly, something that would look more like:
// does not compile
List<int> mapFoos(List<Foo> foos) {
return foos.map(Foo.v2);
}
But this fails to compile with the error:
The argument type '() → int' can't be assigned to the parameter type '(Foo) → int'
Is there some way to turn the member function into a lambda in a succinct way, so that
we can have something closer to the second example.
I could write
int applyV2(Foo f) {
return f.v2();
}
List<int> mapFoos(List<Foo> foos) {
return foos.map(applyV2);
}
but then I'd need to create that for each member function I want to map, which isn't really any better than using the lambda function.
If it makes any difference I'm using dart 1 due to "legacy reasons", if this has changed in recent versions I'd love to know that too.
No.
There is no shorter way to create a function which takes a Foo and calls its v2 method, than (f) => f.v2().
You can omit the Foo type on the parameter, because it can be inferred from the context (a List<X>.map<R> requires an R Function(X) as argument).
You cannot tear off Foo.v2 because v2 is an interface method, not a static method.
Just to elaborate on why Dart doesn't allow that, you can stop reading now if you just want to know what works:
Some languages allow you to tear off instance methods, so Foo.v2 becomes a function which expects its this object as an argument, in Dart a function of type int Function(Foo). Dart does not allow that. Probably for many different reasons, but most importantly because it cannot work. Dart types are interfaces, all class types can be implemented by another class without inheriting any implementation.
If you then tear off Foo.v2, you can call it with an instance of another class which implements Foo, but which won't necessarily find the private fields that Foo has, and which v2 could depend on.
Also, the tear-off would be covariant in its this-parameter.
Take SubFoo which extends Foo and has its own v2 method. If you do Foo foo = SubFoo(); var vtoo = foo.v2; then the static type of vtoo will be int Function(Foo), but the implementation from SubFoo will necessarily have runtime type int Function(SubFoo), which is not a subtype of the static type. That means it's unsound. The torn off function will have to do a run-time type check that its argument is actually a SubFoo, and throw if it's not. (So, that feature is not a good match for Dart.)

How can I print the name of a generic type?

I have a dart method that takes a generic type.
At the top of the method I want to print the name of the type that was passed as T, is this possible?
eg
void myMethod<T> () {
print("myMethod called with type="+????);
}
If myMethod is called with myMethod() it would print "myMethod called with type=String".
Yes and no.
You can write
void myMethod<T> () {
print("myMethod called with type=$T");
}
The only problem is that the Dart libraries don't promise that a Type object (which is what T evaluates to) will have a toString which returns the source name of the type in the original program.
It generally does give that string, but if you compile for the web with "minification", it might not keep the source names available.
There is also no promise that the toString of Type won't change in the future, since it is entirely unspecified.

How to invoke this Objective-C Class Method in Swift 3.0?

I wanted to invoke a OC Class Method with an block in Swift 3.0:
#interface API : NSObject
+ (void)GetCommissionInfoWithModel:(CommissionInfoRequestModel*)model returnInfo:(void (^)(CommissionInfoResponseModel*resModel))callBackBlock;
I tried to invoke it like:
API.GetCommissionInfoWithModel(CommissionInfoRequestModel...
but I don't know how to continue. I know how to invoke a simple method like:
API.test()
API.test(para1:"1",para2:"2")
but with a block, it makes me confused.
I have tried:
let someModel: CommissionInfoRequestModel = CommissionInfoRequestModel.model()
but I got another error:
model()is unavailable : use object construction ‘BaseModel()
Yes the CommissionInfoRequestModel is inherited from "BaseModel", but why I can't use CommissionInfoRequestModel()?
Than I got an error below:
Cannot convert value of type '(CommissionInfoResponseModel) -> ()' to expected argument type '((CommissionInfoResponseModel?) -> Void)!'
when I used the code like:
API.GetCommissionInfoWithModel(someModel1){
(resModel: CommissionInfoResponseModel) in
// Response available in 'resModel' parameter...
}
Try this:
let someModel: CommissionInfoRequestModel = ...
API.GetCommissionInfoWithModel(someModel) {
resModel in
// Response available in 'resModel' parameter...
}
which is just syntax sugar for this longer form:
API.GetCommissionInfoWithModel(someModel, returnInfo: {
(resModel: CommissionInfoResponseModel?) in
...
})
In both versions, the last argument is a closure:
Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
For more info, please see The Swift Programming Language book.

Why does the F# compiler give an error for one case but not the other?

I'm working on a platform invoke call from F#, and I am getting a compiler error I really can't make that much sense out of. First, let me show the C signature of what I am doing:
int Foo(
ULONG_PTR *phHandle,
DWORD flags
);
In F#, I think the correct way to invoke this natively is as so:
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
[<Out>]nativeint& phHandle,
uint32 flags
)
If I try to call this in a class, I get a compilation error when calling it like so:
type Class1() =
[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
member this.Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
The error is:
A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Weirdly, when I do this all in a module, the compilation errors go away:
module Module1 =
[<DllImport("somedll.dll")>]
extern int APlatformInvokeCall
(
nativeint& phHandle,
uint32 flags
)
let Foo() =
let mutable thing = nativeint 0
APlatformInvokeCall(&thing, 0u) |> ignore
thing
Why does this compile as a module, but not as a class?
I don't think it's valid to define an extern method within a class in F#.
If you pull up the F# 3.0 language specification and search for DllImport, near the bottom is a table listing some special attributes and how they can be used. The text for [<DllImport>] says:
When applied to a function definition in a module, causes the F# compiler to ignore the implementation of the definition, and instead compile it as a CLI P/Invoke stub declaration.
That seems to indicate that it's only valid to declare extern methods (that use [<DllImport>]) on functions defined in a module; it doesn't say anything about class members though.
I think you're running into a compiler bug. Please submit this code to fsbugs#microsoft.com so they can fix the error message emitted by the compiler -- it should really be giving you an error about defining an extern method in a class since that's not allowed by the language spec.
Whether this is a bug not withstanding, maybe this is what's going on: If APlatformInvokeCall were considered a static member function, that member have a single argument of tuple type. Tuples are compiled into objects of generic type (see here, at the bottom, or 5.1.3 in the spec). In this case that tuple is
System.Tuple<nativeint&, uint32>
But ECMA 335 II.9.4 says you can't instantiate generic types at byref types. This explains the error reported.
This explanation fits the fact mentioned above that Class1 works (well, compiles) if you modify the extern declaration and call to take instead a single argument. It also fits the fact that the module version works, since in that version there is no considering APlatFormInvokeCall a member function.
The simple solution is to check the spec, here is the class definition grammar:
type type-name pat_opt as-defn)opt =
class
class-inherits-decl_opt
class-function-or-value-defns_opt
type-defn-elements
end
then we have
class-function-or-value-defn :
attributes_opt staticopt let rec_opt function-or-value-defns
attributes_opt staticopt do expr
which doesn't allow extern.
and
type-defn-element :
member-defn
interface-impl
interface-signature
which isn't what you want either.
As a result, we can see that using extern as you are trying to use it can't be done inside a class.

Getting the parameters of a method call from a clang match callback

I'm adapting the Clang tool-template (as described here) to search for a particular method call in my code. In order to later rewrite that call, I would like to get the type of the parameters the method was called with, as well as the type of the object the method was called on.
I managed to find a matcher that calls back the following:
class AddListenerPrinter : public MatchFinder::MatchCallback
{
public :
virtual void run(const MatchFinder::MatchResult &Result) {
if (const auto *FS = Result.Nodes.getNodeAs<clang::MemberExpr>("ListeningBound"))
{
FS->dump();
}
}
};
which prints out:
MemberExpr 0x7fb05b07b948 '<bound member function type>' .addListener 0x7fb05b077670
`-MemberExpr 0x7fb05b07b918 'class MyCore' lvalue ->mCore 0x7fb05b078e30
`-CXXThisExpr 0x7fb05b07b900 'class MyComponent *' this
Now I can't find any way to retrieve the type of the object the method was called on (here class MyCore) or the type of the method argument (here class MyComponent).
How can I do this?
I found the answer by browsing the code of the existing matchers.
Using matcher = memberCallExpr( callee(methodDecl(hasName("addListener"))) )
I was able to retrieve a CXXMemberCallExpr node. Then getting the type of the object the method was called on:
// FS is the CXXMemberCallExpr
// Prints out the type of x in x.method()
llvm::outs() << FS->getRecordDecl()->getName();
and the method parameters are accessible through FS->getArg(n).
Bottom line is: Find the CXX object that contains what you're looking for first (e.g. which class has methods to access function arguments?), then find the matcher that will return the same type of object in ASTMatchers.h.
Hoping this can help anybody else with the same problem.

Resources