Is there a way to declare a function such that I don't care about return value? For example I have this Array extension:
extension Array {
func forEach(function: (element: T) -> ()) {
for e in self {
function(element: e)
}
}
}
Now I want to do:
textFields.forEach{$0.resignFirstResponder()}
And I can't because the function is declared to return Void.
This would fix it:
textFields.forEach{$0.resignFirstResponder();return}
But is there a generic way to declare the function such that I can return any value or Void?
Thanks!
If you add a second generic parameter with no constraints, and type the function to return it, then any return value would be accepted:
extension Array {
func forEach<U>(function: (Element) -> U) {
for e in self {
function(e)
}
}
}
func f(i: Int)->Int {
return i * 2
}
func g(i: Int) -> Double {
return Double(0.0)
}
func h(i: Int) {
println("\(i)")
}
let a = [1,2,3]
a.forEach(g) // U will be an Int
a.forEach(f) // U will be a Double
a.forEach(h) // U will be a ()
However, I’d strongly suggest you not do this and use for…in instead.
The only purpose of running a function on an array but not using the return value is for side-effects. When writing in a more imperative style and using side-effects and external state (as opposed to a more declarative functional style) it’s much better to use for…in as a signal that this is what you’re doing.
There are also unpleasant gotchas involved in constructing your own pseudo-control structures. For example, think about this:
// function that does something side-effecty, but
// if it achieves some goal, exist early
func someFunc(a: [Int]) {
a.forEach { i -> () in
// goal achieved early,
// return from func
return
}
assert(false)
}
This is a common practice – cut out of a function early if some goal (or failure) is achieved. But with the forEach structure this is a bit misleading. It looks like a regular loop, but it’s actually a closure, and the return returns from that closure, ready for forEach to call the next one (essentially, it behaves like a continue in a regular loop).
Use map():
let textFields : [UITextField] = [] // or whatever
textFields.map{$0.resignFirstResponder()}
This way you don't have to specify the return type, and you don't need to reinvent map with your forEach extension.
Related
Someone know how can I define an interface for a class method like:
wrap(fn) {
return function(){
... // do something
fn()
}
}
I'm crashing my head around this, basically how can I define the type of a parameter (and a return value) to be function?
I'm supposing you wanted to return another function that have identical type of fn.
class Wrapper {
// generic for any fn, without handling parameter type
// a return type is not required: tsc infers from `return` statement.
wrap<T extends Function>(fn: T) {
return function () {
// NOTE this version does not handle types of parameters.
// you will have to use `arguments`
return fn();
} as any as T;
}
// generic for all unary fn
// we can have correct type of arg1 in this way
wrapF1<P1, R>(fn: (arg1: P1) => R) {
const wrapped = function (arg1: P1) {
return fn(arg1);
}
return wrapped;
}
// wrapF2, wrapF3, if you need more
}
I might be trying to achieve the impossible but here goes.
I want to define a function ( function A ) which will return the same type as a new function passed into the parameter of function A.
e.g.
export function test<T> ( arg:Function ):T {
return arg;
}
function a():string {
return 'a';
}
function b():number {
return 0;
}
let aVal:string = test(a);
let bVal:number = test(b);
Obviously this will allow me to strongly type my responses for some compile time errors.
Does anyone have any ideas or know if I'm just dreaming.
** Note: Code slapped together for demo **
Cheers
How about this?
function test<T>(arg: () => T): T {
return arg();
}
function a(): string {
return 'a';
}
function b(): number {
return 0;
}
let aVal: string = test(a);
let bVal: number = test(b);
Instead of using the Function interface we defined arg as a function that takes no arguments and returns something of type T. The actual type T then can be defined by the function that's passed in.
In a Swift app, I've created an enum with a function that takes an array of CLBeacon objects as it's only argument (i.e., [CLBeacon]). I get no clang errors with the enum, however when I try to use the enum, clang complains that I can't invoke the function with an argument list of ([CLBeacon]). Here's the code:
enum BeaconArrayState {
case NoObjectOnScreen, FirstObjectOnScreen, FirstObjectOffScreen
mutating func check(beacons: [CLBeacon]) -> BeaconArrayState {
switch self {
case FirstObjectOnScreen:
return .FirstObjectOnScreen
case FirstObjectOffScreen:
return .FirstObjectOffScreen
case NoObjectOnScreen:
if beacons.count > 0 {
println("push to screen associated with beacon \(beacons[0].minor)")
}
return .NoObjectOnScreen
}
}
}
var beaconArrayState: BeaconArrayState = .NoObjectOnScreen
func beaconManager(manager: AnyObject!, didRangeBeacons beacons: [AnyObject]!, inRegion region: CLBeaconRegion!) {
let knownBeacons = beacons.filter{$0.proximity != CLProximity.Unknown}
//send updated beacons array to perform parseBeacons
NSNotificationCenter.defaultCenter().postNotificationName("updateNotificationPriorities", object: knownBeacons)
beaconArrayState = BeaconArrayState.check(knownBeacons as [CLBeacon])
}
This gives: the error - Cannot invoke 'check' with argument list of type '([CLBeacon])'
The code in the case statements is irrelevant for now and not yet determined, but why the error on invocation?
The problem with your code is that you are calling check method statically while that function is not static at all. Also check function its not a mutating function so you dont need mutating keyword. To make this work make the follow change beaconArrayState = beaconArrayState.check(knownBeacons as [CLBeacon]) or if you want check method to mutate itself then change it like this :
mutating func check(beacons: [CLBeacon]) {
switch self {
case FirstObjectOnScreen:
self = .NoObjectOnScreen
case FirstObjectOffScreen:
self = .FirstObjectOffScreen
case NoObjectOnScreen:
if beacons.count > 0 {
println("push to screen associated with beacon \(beacons[0].minor)")
}
self = .NoObjectOnScreen
}
}
then just call beaconArrayState.check(knownBeacons as [CLBeacon]) and becaonArrayState will get its new value
I have a simple class where I declare a block as a variable:
class MyObject : NSObject
{
var progressBlock:(progress:Double) -> ()?
init() { }
}
As far as I understand, if defined this way, progressBlock does not have to be initialized in the init() initializer
However, when I try to compile I get his error:
Property 'self.progressBlock' not initialized at super.init
So the question is, how do I create an optional progressBlock, so I don't get this error?
The way you have written it, the compiler assumes progressBlock is a closure that returns an optional empty tuple instead of an optional closure that returns an empty tuple. Try writing it like this instead:
class MyObject:NSObject {
var progressBlock:((progress:Double) -> ())?
init() {
progressBlock = nil
progressBlock = { (Double) -> () in /* code */ }
}
}
Adding to connor's reply. An optional block can be written as:
var block : (() -> ())? = nil
Or as an explicit Optional:
var block : Optional<() -> ()> = nil
Or better yet, with a custom type
typealias BlockType = () -> ()
var block : BlockType? = nil
I am new to ActionScripting but I have done some Java. I was told they are kinda similar. I am coding my swf file with some AS3 integrated.
function init():void{
// do something
}
function init(var string:String):String{
// do something else
}
is this not allowed in AS? If not, is there another way of handling it besides?
Thanks in advance.
Yes, you can override functions. But the example you gave is not overriding - it's overloading. For overriding a function, you basically just create a function with the same signature and everything in a subclass and add the word "override" right before it.
You can't directly overload a function though. If you want a variable number of parameters, you have to use optional parameters instead. Like this:
function init(str:String = null):String
{
if (str == null)
{
// do one thing
return null;
}
else
{
// do another thing
return "someString";
}
}
And that's about the best you're going to be able to do in AS3. The inability to overload functions, at least strictly speaking, is a fairly common complaint and obvious shortcoming of the language.
Do you mean method overloading? Actionscript, sadly, does not support this.
To get around it, you can use default parameters, or just make your parameters a bit less constraining. This answer has some details on that.
You could try this:
function init(var string:String = "Default value"):String{
// do something
}
Actionscript does not support method overloading. However, based on the answer to this question you have other options.
If you just want to be able to accept any type, you can use * to
allow any type:
function someFunction( xx:*, yy:*, flag:Boolean = true )
{
if (xx is Number) {
...do stuff...
} else if (xx is String) {
...do stuff...
} else {
...do stuff...
}
}
If you have a large number of various parameters where order is
unimportant, use an options object:
function someFunction( options:Object )
{
if (options.foo) doFoo();
if (options.bar) doBar();
baz = options.baz || 15;
...etc...
}
If you have a variable number of parameters, you can use the ...
(rest) parameter:
function someFunction( ... args)
{
switch (args.length)
{
case 2:
arr = args[0];
someBool = args[1];
xx = arr[0];
yy = arr[1];
break;
case 3:
xx = args[0];
yy = args[1];
someBool = args[2];
break;
default:
throw ...whatever...
}
...do more stuff...
}
For cases where you need to call a common function to a number of
classes, you should specify the interface common to each class:
function foo( bar:IBazable, flag:Boolean )
{
...do stuff...
baz = bar.baz()
...do more stuff...
}