Possible Swift 3 Compiler bug: concatenating arrays of [UIButton]! - uibutton

I think I’ve just found the strangest bug in the swift compiler
If you try to concatenate two implicitly unwrapped arrays of buttons, works fine, but as soon as you try to concatenate a third array of the same type, it says binary operator '+' cannot be applied to types [UIButton] and [UIButton]! even though the first two arrays are implicitly unwrapped...
As in…
#IBOutlet var buttons1: [UIButton]!
#IBOutlet var buttons2: [UIButton]!
#IBOutlet var buttons3: [UIButton]!
var allButtons = button1 + button2 //this works
var allButtons = buttons1 + buttons2 + buttons3 //this doesn't…
Have duplicated this in a playground as well.
EDIT:
It looks like part of the problem is that the concatenation of button1 + button2 produces a [UIButton] instead of [UIButton]!, even if I force unwrap the concatenation like so:
var allButtons = button1! + button2!
Also, even if I force the type of the variable it still doesn't work:
var allButtons: [UIButton]! = button1 + button2 + button3
Is this just something I'm blatantly missing, or is this a real bug?
EDIT 2
Well I found two workarounds. They both make sense given the result the concatenation of the first two arrays produces, but I still find it strange that the compiler wouldn't infer the types of all three given the statement. Is this expected behavior...?
var anotherAllButtons = button1 + button2 + (button3 as [UIButton])
var allButtons = (button1 + button2) as [UIButton]! + button3
Interestingly, the cast from [UIButton] to [UIButton]! would never fail, which makes me suspect that the compiler would infer the types correctly.

Related

Godot/GDScript Grid Movement Tweening

So I've been using KidsCanCode's Godot tutorials/documentation to help me create a Pokemon-like grid-based movement for a project I'm working on. For all intents and purposes, I would like to create a movement system as close to that in the earlier handheld Pokemon games as possible.
I would like to add two things before I start; one, I have grown fond of the way KidsCanCode attempted to teach grid-based movement, so while other ways of coding it may be simpler such as those that can be found on videos such as this one (https://www.youtube.com/watch?v=jSv5sGpnFso), I would like to hard-headidly stick to this method of coding it... you'll see what I mean when you read the code. Lastly, I would like to add that I had this code working before ! I actually haven't made any changes to the code since it was last working, however, for some reason it no longer seems to work, I'm not sure if that's due to Godot updating since, but hopefully someone can help me out with that.
So first of all, this is my player scene node tree. The most important parts of this being the RayCast2D and Tween nodes.
And this is my code for the main Area2D Player node:
extends Area2D
const tile_size = 16
export var speed = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event):
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir):
$Tween.interpolate_property(self, "position", position,
position + inputs[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
To quickly explain, func _ready(): snaps the player to the grid. func _unhandled_input(event): then checks to see if a Tween is occurring, and if not, calls func move(dir). This function raycasts to the given direction input, forces a raycast update, and if no static body is in the given direction, calls func move_tween(dir). This last functions handles tween interpolation to the given direction and starts the tweening process. That's pretty much it. Once again, this used to work just fine.
However, now when I try to run this, I get an error "Invalid get index '(0, 1)' (on base: 'Dictionary')" where "(0, 1)" changes based on what direction I tried to move in when the game was running.
In the Debugger dock, underneath Stack Frames, it gives me errors on lines "22 - at function; move" $RayCast2D.cast_to = inputs[dir] * tile_size and "19 - at function: _unhandled_input" move(inputs[dir]).
The code on the website had these say (dir) only instead of (inputs[dir]). But doing so only gives me another error. If anyone smarter than me has any idea what's going on, I would very much appreciate any and all insight. Thank you !
Understanding the problem
Alright, let us see. The variable inputs has your dictionary:
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
The keys are String, and the values are Vector2.
Thus, here:
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
The variable dir is going to be a String. Which is what you need for is_action_pressed, so that is correct.
And inputs[dir] is going to be a Vector2. Which means that in move you are getting a Vector2 as argument.
Now, in move you say::
func move(dir):
$RayCast2D.cast_to = inputs[dir] * tile_size
But remember that the argument you are passing is a Vector2, and the keys of input are all String. So it fails here: inputs[dir].
Early warning for similar problems
Using types can help you identify this kind of problems early. Sadly in Godot 3.x there is no way to specify the the keys and values of a Dictionary.
Arguably you could use C# and use .NET Dictionary<TKey,TValue> from the System.Collections.Generic, which would let you specify the key and value types. Yet, we are not talking about those dictionaries here.
What you can tell with GDScript is that your parameters are either Vector2:
func move(displacement:Vector2):
# …
Or String
func move(dir:String):
# …
This way Godot can tell you when you are calling them with the wrong parameter.
Another thing that will help. Although it is more on the discipline side, is to keep consistent names. If the names you use have a concrete meaning in your system, they will help you.
For instance, you call move like this:
move(inputs[dir])
Meaning that what you are passing is not called dir※. But you have move defined like this:
func move(dir):
# …
So move expects something you call a dir. And you would see that when you are typing the call to move.
※: I'd say you are passing one of the values of inputs, so what you are passing is called an input. Or you could call them action, given that you use them in is_action_pressed. Which, again, would be using names in a way that helps you.
Solving the problem
The way I would solve this is by using the String and inputs in _unhandled_input only (after all, that function is meant to deal with inputs). And work with Vector2 from there on. This means that:
The other methods would also be useful if in the future you wanted a movement that does not come from one of the inputs.
You are not repeating the effort of looking up in the Dictionary.
Admittedly, these aren't a huge deal for your game right now. And ultimately what you do is up to you. Yet, consider this approach submitted to your consideration.
This is the code (I have added some type annotations):
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(inputs[dir])
func move(displacement:Vector2) -> void:
$RayCast2D.cast_to = displacement * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(displacement)
func move_tween(displacement:Vector2) -> void:
$Tween.interpolate_property(self, "position", position,
position + displacement * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Or you can using String thought out, and querying the dictionary every time. Which, I believe, is what you intended. Like this:
extends Area2D
const tile_size:float = 16
export var speed:float = 5
var inputs = { "ui_right": Vector2.RIGHT,
"ui_left": Vector2.LEFT,
"ui_up": Vector2.UP,
"ui_down": Vector2.DOWN }
func _ready():
position = position.snapped(Vector2.ONE * tile_size/2)
func _unhandled_input(event:InputEvent) -> void:
if $Tween.is_active():
return
for dir in inputs.keys():
if event.is_action_pressed(dir):
move(dir)
func move(dir:String) -> void:
$RayCast2D.cast_to = input[dir] * tile_size
$RayCast2D.force_raycast_update()
if !$RayCast2D.is_colliding():
move_tween(dir)
func move_tween(dir:String) -> void:
$Tween.interpolate_property(self, "position", position,
position + input[dir] * tile_size, 1.0/speed, Tween.TRANS_SINE, Tween.EASE_IN_OUT)
$Tween.start()
Notice here that _unhandled_input is passing dir to move. The same way that move is passing dir to move_tween.

Modifying self in `iter_mut().map(..)`, aka mutable functional collection operations

How do I convert something like this:
let mut a = vec![1, 2, 3, 4i32];
for i in a.iter_mut() {
*i += 1;
}
to a one line operation using map and a closure?
I tried:
a.iter_mut().map(|i| *i + 1).collect::<Vec<i32>>();
The above only works if I reassign it to a. Why is this? Is map getting a copy of a instead of a mutable reference? If so, how can I get a mutable reference?
Your code dereferences the variable (*i) then adds one to it. Nowhere in there does the original value get changed.
The best way to do what you asked is to use Iterator::for_each:
a.iter_mut().for_each(|i| *i += 1);
This gets an iterator of mutable references to the numbers in your vector. For each item, it dereferences the reference and then increments it.
You could use map and collect, but doing so is non-idiomatic and potentially wasteful. This uses map for the side-effect of mutating the original value. The "return value" of assignment is the unit type () - an empty tuple. We use collect::<Vec<()>> to force the Iterator adapter to iterate. This last bit ::<...> is called the turbofish and allows us to provide a type parameter to the collect call, informing it what type to use, as nothing else would constrain the return type.:
let _ = a.iter_mut().map(|i| *i += 1).collect::<Vec<()>>();
You could also use something like Iterator::count, which is lighter than creating a Vec, but still ultimately unneeded:
a.iter_mut().map(|i| *i += 1).count();
As Ry- says, using a for loop is more idiomatic:
for i in &mut a {
*i += 1;
}

Trying to switch a direct integer value with a variable in swift

I'm trying to switch out a direct integer with a variable in swift, but for some reason I'm getting this error and I have no idea. The end goal is to get my currentValue (line 76) to replace the 100's on line 41 - could anyone let me know how I could accomplish this without the error? New to swift and having a hard time (background in objective-c, figured something this simple would not stop me in my tracks!)
Full .swift file here: http://pastebin.com/K6UHkNEv
EDIT:
// these values change the number of squares
let _gameView = CGOLView(gridWidth:100, gridHeight:100)
#IBOutlet weak var tileSizeSlider: UISlider!
#IBAction func sliderValueChanged(sender: UISlider) {
var currentValue = Int(sender.value)
print("\(currentValue)")
}
should work as:
// these values change the number of squares
let _gameView = CGOLView(gridWidth:currentValue, gridHeight:currentValue)
#IBOutlet weak var tileSizeSlider: UISlider!
#IBAction func sliderValueChanged(sender: UISlider) {
var currentValue = Int(sender.value)
print("\(currentValue)")
}
instead I get this error:
Use of unresolved identifier 'currentValue'
and if I try to create custom int's and input them:
var gridWidthValue = 50
var gridHeightValue = 50
like this:
let _gameView = CGOLView(gridWidth:gridWidthValue, gridHeight:gridHeightValue)
I get:
'ViewController.Type' does not have a member named 'gridHeightValue'
Any help would be appreciated - thanks stackoverflow community!
David.
currentValue is a local variable to sliderValueChanged.
Instead you should instantiate _gameView in init. Note however, you still won't be able to use currentValue.
If this is a one off sort of thing, you can always make _gameView an optional and then create it when you have adjusted the slider. This is admittedly a little clumsy.
I am not familiar with Conway's Game of Life, but looking at the code, it seems CGOLView's init does some adjustment based on the grid width and height. The reason I am mentioning this is that you could always change the view's frame size, however, you'd then also need to make some other mods to the tileViews for it to look proper.
As to why gridWidthValue/gridHeightValue is not working. Those are properties defined in an instance. Hence you would need to do somethign like self.gridWithValue to reference it. However, you cannot do that when defining the property such as
let _gameView = CGOLView(gridWidth:gridWidthValue, gridHeight:gridHeightValue)
This is also why instantiating _gameView in init is the way to go.
Your problem is that you cannot access the variable currentValue because it is inside of a function. You have to declare that value outside of the function to be able to use it outside of the function.

xcode beta bridgeToObjectiveC alternative?

I am currently making a calculator app and I need to use the bridgeToObjectiveC code but that is no longer available in the current beta version of xcode 6. This is the code I need to write:
#IBAction func btnAdditionCalculate(sender: AnyObject) {
let firstNumber = txtAdditionFirst.text.bridgeToObjectiveC().floatValue
let secondNumber = txtAdditionSecond.text.bridgeToObjectiveC().floatValue
let answer = firstNumber + secondNumber
var answerFormat: NSString = NSString(format: "%0.0f", answer)
labelAdditionAnswer.text = " \(answerFormat)"
}
I know I need to use NSString and I tried to do this but it doesn't work:
#IBAction func btnAdditionCalculate(sender: AnyObject) {
let firstNumber = (txtAdditionFirst.text as NSString).floatValue
let secondNumber = (txtAdditionSecond.text as NSString).floatValue
let answer = firstNumber + secondNumber
var answerFormat: NSString = NSString(format: "%0.0f", answer)
labelAdditionAnswer.text = " \(answerFormat)"
}
Thanks for all your help
edit 8/15
When I run the code on the iOS simulator, the app loads and I am able to put numbers into the number 1 and number 2 slot, however when I press calculate xcode highlights the let firstNumber line and says Thread 1:EXC_BAD_INSTRUCTION and this is the error message I get:
2014-08-15 16:14:53.019 Innovative Calculator p1[578:8032] Can't find keyplane that supports type 4 for keyboard iPhone-Portrait-NumberPad; using 3876877096_Portrait_iPhone-Simple-Pad_Default
2014-08-15 16:14:55.425 Innovative Calculator p1[578:8032] Can't find keyplane that supports type 8 for keyboard iPhone-Portrait-DecimalPad; using 1425143906_Portrait_iPhone-Simple-Pad_Default
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
If your code is halting on let firstNumber = ... with a nil optional conversion, it means you are incorrectly assuming that either txtAdditionFirst or textAdditionFirst.text is not nil. UITextField makes assurances that .text is never nil so the best bet is that you failed to wire up txtAdditionFirst in Interface Builder.
You can verify this by checking the variable definition to see it it is filled in or set a breakpoint above the line and see if it is nil.
If you have a valid reason for the variable to be nil, you have a couple options for doing this:
// The long way (mutable)
var firstNumber:Float = 0
if let value = textField?.text {
firstNumber = (value as NSString).floatValue
}
// The short way (not mutable)
let firstNumber = (textField?.text? as NSString?)?.floatValue ?? 0.0
The first way sets the number to zero initially then uses optional chaining to test if textField and textField.text are not nil. The second way uses optional chaining the whole way to get an optional float value, then unwraps it if not nil or falls back to 0.

Is it possible to indirectly load a value type on the stack

In Microsoft IL, to call a method on a value type you need an indirect reference. Lets say we have an ILGenerator named "il" and that currently we have a Nullable on top of the stack, if we want to check whether it has a value then we could emit the following:
var local = il.DeclareLocal(typeof(Nullable<int>));
il.Emit(OpCodes.Stloc, local);
il.Emit(OpCodes.Ldloca, local);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
However it would be nice to skip saving it as a local variable, and simply call the method on the address of the variable already on the stack, something like:
il.Emit(/* not sure */);
var method = typeof(Nullable<int>).GetMethod("get_HasValue");
il.EmitCall(OpCodes.Call, method, null);
The ldind family of instructions looks promising (particularly ldind_ref) but I can't find sufficient documentation to know whether this would cause boxing of the value, which I suspect it might.
I've had a look at the C# compiler output, but it uses local variables to achieve this, which makes me believe the first way may be the only way. Anyone have any better ideas?
**** Edit: Additional Notes ****
Attempting to call the method directly, as in the following program with the lines commented out, doesn't work (the error will be "Operation could destabilise the runtime"). Uncomment the lines and you'll see that it does work as expected, returning "True".
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
//var local = il.DeclareLocal(typeof(Nullable<int>));
//il.Emit(OpCodes.Stloc, local);
//il.Emit(OpCodes.Ldloca, local);
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
So you can't simply call the method with the value on the stack because it's a value type (though you could if it was a reference type).
What I'd like to achieve (or to know whether it is possible) is to replace the three lines that are shown commented out, but keep the program working, without using a temporary local.
I figured it out! Luckily I was reading about the unbox opcode and noticed that it pushes the address of the value. unbox.any pushes the actual value. So, in order to call a method on a value type without having to store it in a local variable and then load its address, you can simply box followed by unbox. Using your last example:
var m = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
var il = m.GetILGenerator();
var ctor = typeof(Nullable<int>).GetConstructor(new[] { typeof(int) });
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Box, typeof(Nullable<int>)); // box followed by unbox
il.Emit(OpCodes.Unbox, typeof(Nullable<int>));
var getValue = typeof(Nullable<int>).GetMethod("get_HasValue");
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(m.Invoke(null, null));
The downside to this is that boxing causes memory allocation for the boxed object, so it is a bit slower than using local variables (which would already be allocated). But, it saves you from having to determine, declare, and reference all of the local variables you need.
If the variable is already on the stack, you can go ahead and just emit the method call.
It seems that the constructor doesn't push the variable on the stack in a typed form. After digging into the IL a bit, it appears there are two ways of using the variable after constructing it.
You can load the variable that will store the reference onto the evaluation stack before calling the constructor, and then load that variable again after calling the constructor like so:
DynamicMethod method = new DynamicMethod("M", typeof(bool), Type.EmptyTypes);
ILGenerator il = method.GetILGenerator();
Type nullable = typeof(Nullable<int>);
ConstructorInfo ctor = nullable.GetConstructor(new Type[] { typeof(int) });
MethodInfo getValue = nullable.GetProperty("HasValue").GetGetMethod();
LocalBuilder value = il.DeclareLocal(nullable);
// load the variable to assign the value from the ctor to
il.Emit(OpCodes.Ldloca_S, value);
// load constructor args
il.Emit(OpCodes.Ldc_I4_6);
il.Emit(OpCodes.Call, ctor);
il.Emit(OpCodes.Ldloca_S, value);
il.Emit(OpCodes.Call, getValue);
il.Emit(OpCodes.Ret);
Console.WriteLine(method.Invoke(null, null));
The other option is doing it the way you have shown. The only reason for this that I can see is that the ctor methods return void, so they don't put their value on the stack like other methods. It does seem strange that you can call Setloc if the new object isn't on the stack.
After looking at the options some more and further consideration, I think you're right in assuming it can't be done. If you examine the stack behaviour of MSIL instructions, you can see that no op leaves its operand(s) on the stack. Since this would be a requirement for a 'get address of stack entry' op, I'm fairly confident one doesn't exist.
That leaves you with either dup+box or stloc+ldloca. As you've pointed out, the latter is likely more efficient.
#greg: Many instructions leave their result on the stack, but no instructions leave any of their operands on the stack, which would be required for a 'get stack element address' instruction.
Just wrote a class that does what the OP is asking... here's the IL code that C# compiler produces:
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: newobj instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_000f: stfld valuetype [mscorlib]System.Nullable`1<int32> ConsoleApplication3.Temptress::_X
IL_0014: nop
IL_0015: ret