How to Pass a Class Type as a Function Parameter

How to pass a class type as a function parameter

You are approaching it in the wrong way: in Swift, unlike Objective-C, classes have specific types and even have an inheritance hierarchy (that is, if class B inherits from A, then B.Type also inherits from A.Type):

class A {}
class B: A {}
class C {}

// B inherits from A
let object: A = B()

// B.Type also inherits from A.Type
let type: A.Type = B.self

// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self

That's why you shouldn't use AnyClass, unless you really want to allow any class. In this case the right type would be T.Type, because it expresses the link between the returningClass parameter and the parameter of the closure.

In fact, using it instead of AnyClass allows the compiler to correctly infer the types in the method call:

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
// The compiler correctly infers that T is the class of the instances of returningClass
handler(returningClass())
}

Now there's the problem of constructing an instance of T to pass to handler: if you try and run the code right now the compiler will complain that T is not constructible with (). And rightfully so: T has to be explicitly constrained to require that it implements a specific initializer.

This can be done with a protocol like the following one:

protocol Initable {
init()
}

class CityInfo : NSObject, Initable {
var cityName: String?
var regionCode: String?
var regionName: String?

// Nothing to change here, CityInfo already implements init()
}

Then you only have to change the generic constraints of invokeService from <T> to <T: Initable>.

Tip

If you get strange errors like "Cannot convert the expression's type '()' to type 'String'", it is often useful to move every argument of the method call to its own variable. It helps narrowing down the code that is causing the error and uncovering type inference issues:

let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self

CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/

}

Now there are two possibilities: the error moves to one of the variables (which means that the wrong part is there) or you get a cryptic message like "Cannot convert the expression's type () to type ($T6) -> ($T6) -> $T5".

The cause of the latter error is that the compiler is not able to infer the types of what you wrote. In this case the problem is that T is only used in the parameter of the closure and the closure you passed doesn't indicate any particular type so the compiler doesn't know what type to infer. By changing the type of returningClass to include T you give the compiler a way to determine the generic parameter.

How to pass a class type as parameter?

In TypeScript, you can construct a new type, something like:

type Class<T> = new (...args: any[]) => T

Which you can then use this way:

function register(command: Class<Command>) {
new command()
}

This should constrain TypeScript to ONLY accept classes which construct or extend the Command type.

EDIT:

Sorry, missed something when I evaluated your example. Your class Command is generic enough that almost any constructable object will overlap. What it's missing is constraints.

  1. The constructor will take any first argument, undefined or not, so any class which has a constructor accepting zero or one arguments will match
  2. The signature of the object that will be returned is empty, no methods or properties exist to identify it and so any methods/props will "fall-through" and be allowed as an "extension" of your class

We can over come either of these by modifying either properties or methods required for the Command class, thus constraining derived types to that explicit signature

If we want to narrow the possible matches by adding a method or property specific to Command, then we get the desired behavior you've outlined.

export namespace customCommand {
export type Class<T> = new (...args: any[]) => T

export class Command {
public constructor(parameter?: any) {

}

picard (): string {
return 'Make it so.'
}
}

export function register(command: Class<Command>) {
new command()
}
}

/*
Argument of type 'MapConstructor' is not assignable to
parameter of type 'Class<Command>'. Property 'picard'
is missing in type 'Map<any, any>' but required in
type 'Command'. ts(2345)
*/
customCommand.register(Map)

/*
Argument of type 'ObjectConstructor' is not assignable to
parameter of type 'Class<Command>'. The 'Object' type is
assignable to very few other types. Did you mean to use
the 'any' type instead? Property 'picard' is missing in
type 'Object' but required in type 'Command'. ts(2345)
*/
customCommand.register(Object)

/* No error */
customCommand.register(customCommand.Command)

How to pass class type as an parameter to function?

You could do something like this:

List<A> list = (...);

public static void print(Class klass) {
for(A a : list) {
if(klass.isInstance(a)) {
System.out.println(a);
}
}
}

To use it:

print(C.class);

Or

C c = new C();

print(c.getClass());

Pass class type as a function parameter and use as? to cast the class

Swift 4.2

You can use a generic function and restrict the type parameter to be a Section.

import Foundation

class Section {}
class TimeSection: Section {}
class TaskSection: Section {}
class NoSection {}

let timeSection = TimeSection()
let taskSection = TaskSection()

let sections = [timeSection, taskSection]

func findSection<T: Section>(from classType: T.Type) {
for section in sections {
guard let section = section as? T else { continue }

print("Found section: \(section)")
}
}

findSection(from: TimeSection.self) // Found section: __lldb_expr_9.TimeSection
findSection(from: TaskSection.self) // Found section: __lldb_expr_9.TaskSection
findSection(from: NoSection.self) // won't compile

Python - how to pass to a function argument type of a class object (typing)

Depending on whether you meant to pass a class (type) or an instance of a class, you’re looking for either typing.Type or simply the class.

Here’s a simple example to explain both situations:

from typing import Type, TypeVar


class Vehicle:
def __init__(self):
print("Creating a %s" % self.__class__.__name__)

def move(self):
print("This %s is moving…" % self.__class__.__name__)

TVehicle = TypeVar("TVehicle", bound=Vehicle)

class Car(Vehicle):
def honk(self) -> None:
print("tuuuuut")

class Bike(Vehicle):
def ring(self) -> None:
print("ring")

class Dog:
def bark(self) -> None:
print("woof!")


def move(v: Vehicle) -> None:
v.move()

def instantiate(class_to_instantiate: Type[TVehicle]) -> TVehicle:
return class_to_instantiate() # create an instance

move(Bike())
move(Car())

instantiate(Bike).ring()
instantiate(Car).honk()
#instantiate(Dog)

Car and Bike inherit from Vehicle, so they both get at least the move method and the custom __init__, which reveals the name of the class that invoked it.

Now, in the first function, move, one simply wants to specify that the argument v should be an instance of a Vehicle. The function calls Vehicle’s move method, which will reveal the name of the instance’s class from which the call originated.

In the second function, instantiate, the goal is to create an instance of a class. This works through type variables, which allow you in this example to specify that there’s a relation between the function’s input argument and output argument: if I were to call instantiate(Bike), I want the return type to be an instance of the Bike class, so that I may legally call its ring method. If you were to replace the TVehicle in this function definition simply by Vehicle, your type checking program would complain, because the return type would then be an instance of the Vehicle class, for which you do not have a guarantee that the ring method exists.
Finally, the Type part that you see in the argument of instantiate simply allows you to call the function with a class, so not with an instance of that class. This is useful e.g. in cases where you want to delay instantiation of a class.

Note that this is an example to explain how to do it. In a more professional setting, Vehicle would likely be an abstract base class and some methods here could be given as class methods.

Side notes on your code example:

  1. Note that if you don’t intend to write code that also works in Python2, you shouldn’t inherit from object (ref).
  2. Classes are typically written with CapWord names, as specified in PEP8, the Python style guide. Following this style makes your code more easily understandable by other developers.

How can I pass a class method as a parameter to another function and later call it, preferably making the variable class method signature explicit?

How would I need to change the above code to implement the same thing
using templates instead of std::function + std::bind?

And how about lambdas instead of std::function + std::bind? I
still want to call B:myWay() and B::otherWay() but using lambdas.
I don't want to substitute B:myWay() and B::otherWay() with
lambdas.

You can use a lambda, yes.

Something like [this]() { return myWay(); } that:

  • captures this, and
  • calls a method of the current object.

[Demo]

#include <iostream>  // cout

class A {
protected:
template <typename F>
void complexMethod(F&& f) { f(); }
};

class B : public A {
void myWay() { std::cout << "myWay\n"; }
void otherWay() { std::cout << "otherWay\n"; }
public:
void doingSomething() {
complexMethod([this]() { return myWay(); });
}
void doingAnotherThing() {
complexMethod([this]() { return otherWay(); });
}
};

int main() {
B b{};
b.doingSomething();
b.doingAnotherThing();
}

// Outputs:
//
// myWay
// otherWay

Is there any implementation technique (one of the above or some other)
were I would be able to make variableMethod return type and
parameters explicit? How would I do it?

You could use const std::function<bool(int,double)>& f as the parameter receiving a function for complexMethod. And still pass a lambda. Notice though lambdas are now receiving (int i, double d) (it could be (auto i, auto d) as well).

[Demo]

#include <functional>  // function
#include <ios> // boolalpha
#include <iostream> // cout

class A {
protected:
bool complexMethod(const std::function<bool(int,double)>& f, int i, double d)
{ return f(i, d); }
};

class B : public A {
bool myWay(int a, double b) { return a < static_cast<int>(b); }
bool otherWay(int a, double b) { return a*a < static_cast<int>(b); }
public:
bool doingSomething(int a, double b) {
return complexMethod([this](int i, double d) {
return myWay(i, d); }, a, b);
}
bool doingAnotherThing(int a, double b) {
return complexMethod([this](auto i, auto d) {
return otherWay(i, d); }, a, b);
}
};

int main() {
B b{};
std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
// true
// false

Notice also the same could be accomplished with templates, although you wouldn't be making the signature explicit.

[Demo]

#include <functional>  // function
#include <ios> // boolalpha
#include <iostream> // cout

class A {
protected:
template <typename F, typename... Args>
auto complexMethod(F&& f, Args&&... args) -> decltype(f(args...))
{ return f(args...); }
};

class B : public A {
bool myWay(int a, double b) { return a < static_cast<int>(b); }
bool otherWay(int a, double b) { return a*a < static_cast<int>(b); }
public:
bool doingSomething(int a, double b) {
return complexMethod([this](auto i, auto d) {
return myWay(i, d); }, a, b);
}
bool doingAnotherThing(int a, double b) {
return complexMethod([this](auto i, auto d) {
return otherWay(i, d); }, a, b);
}
};

int main() {
B b{};
std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
// true
// false

Which technique is recommended? Why (speed, flexibility,
readility...)?

Item 34 of Scott Meyer's Effective Modern C++ book is titled Prefer lambdas to std::bind. It ends with a summary saying: Lambdas are more readable, more expressive, and may be more efficient than using std::bind. However, it also mentions a case when std::bind may be useful over lambdas.

Swift - How to use a class type as a parameter / variable

First read Metatype Type in the The Swift Programming Language. Once read continue with the answer.

From that you have learnt that you can declare a function parameter's type to be the type of types (you are allowed to go crosseyed), AKA metatype, and can therefore pass a type to a function. Combine that with generics and Swift's type inference and you could declare your function as:

func sortFileArrayByType<T>(fileAttributeKeyString : String,
attributeType : T.Type,
fileURLArray : [URL]
) -> [(url: URL, attribute: T)]
where T : Comparable

This adds the parameter attributeType whose type is the metatype of T where T will be inferred. For example the metatype String.self could be passed and T will be inferred to be String.

The where clause constrains T so that only types which are Comparable are allowed, this is required to enable the function to do sorting. File attributes can be Date, String and NSNumber valued; unfortunately the latter does not conform to Comparable so you need to add an extension to make it, the following will suffice:

extension NSNumber : Comparable
{
public static func <(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedAscending }
public static func ==(a : NSNumber, b : NSNumber) -> Bool { return a.compare(b) == .orderedSame }
}

Within the body of the function you need to declare your array of tuples to have attributes of type T:

var tupleArrayWithURLandAttribute : [(url: URL, attribute: T)] = []

and when you add entries you need to cast the value returned by attributesOfItem to be T:

tupleArrayWithURLandAttribute.append((url: url, attribute: value as! T))

Note the use of as! here, you must match the attribute name and the type of its value correctly in the function call or you will get a runtime abort. Handling this as a soft error, if needed, is left as an exercise.

There are a number of typos etc. in the code you posted, they are left for you to fix, having done that your function should work. A call might look like:

let ans = sortFileArrayByType2(fileAttributeKeyString: "NSFileCreationDate",
attributeType: Date.self,
fileURLArray: urlArray)

and the type of ans in this case will be [(url: URL, attribute: Date)]

HTH

How to pass a Swift type as a method argument?

You have to use a generic function where the parameter is only used for type information so you cast it to T:

func doSomething<T>(_ a: Any, myType: T.Type) {
if let a = a as? T {
//…
}
}

// usage
doSomething("Hello World", myType: String.self)


Using an initializer of the type T

You don’t know the signature of T in general because T can be any type. So you have to specify the signature in a protocol.

For example:

protocol IntInitializable {
init(value: Int)
}

With this protocol you could then write

func numberFactory<T: IntInitializable>(value: Int, numberType: T.Type) -> T {
return T.init(value: value)
}

// usage
numberFactory(value: 4, numberType: MyNumber.self)


Related Topics



Leave a reply



Submit