Enums and static typing - gdscript

I have declared an enum in some gdscript code.
Then, I want to declare some variables to be of that type of enum.
Is this possible. I know GDScript allows to declare a static type of a var. MEvery language I have used allows you to treat an enum as a var.
The following code produces the following error for me...
enum XDir {
None,
Left,
Right
}
enum YDir {
None,
Up,
Down
}
var x_dir : XDir
var y_dir : YDir
Parser Error: Identifier 'XDir' is not a valid type (not a script or
class), or could not be found on base 'self'.

This is not possible yet. Enums in GDScript are syntactic sugar for constant dictionaries and are not actual types.
You'll have to use int as the type until enums are made into real types.
Do note that you can still give enums to export like
export(XDir) var x_dir: int
To enforce an enum value at runtime you can do:
assert(XDir.has(x_dir))

Related

Swift explicit variable declaration with optional

I'm new to Swift and trying to decode one of the Apple examples. Could someone please explain what this line is doing ?
#SceneStorage("selection") private var selectedProjectID: Project.ID?
Project is a struct conforming to Codable and Identifiable
Is selectedProjectID of the same type as Project.ID? ?
In general for some type, T, T? is syntactic sugar for Optional<T>.
Optional<T> is defined as an enum with special compiler support for comparisons and assignments to nil. It looks something like this.
enum Optional<Wrapped>
{
case none
case some(wrapped: Wrapped)
}
So when an optional is nil, it's actually .none
In comments you asked:
Does the Project.Id bit mean selectedProjectID will be of explicit type the same as the Project.ID member in the struct ?
The answer is no. selectedProjectID is an instance property (a variable) whose type is Optional<Project.ID>. Project.ID is a type. It does also have a type, a meta-type (the type of a type), but I don't think that's what you mean to ask. I think you're asking if selectedProjectID is same type as the id property that is defined in Project as part of its conformance to Identifiable. And the answer is no, not exactly.
If someProject is an instance of Project, then someProject.id is of type Project.ID, whereas selectedProjectID is of type Optional<Project.ID>.
There is a lot of compiler support extracting, comparing and assigning between optionals and their wrapped type, but strictly speaking they are different types, just as much as Int and Array<Int> are different types.
On the other hand, assuming someProjectID is not nil, then someProjectID! (ie, force-unwrapped) is the same type as someProject.id. Similarly in
if let pID = someProjectID {
...
}
within the if, pID is also the same type as someProject.id

Overcoming Type alias '…' references itself

Background
I have an enum which, simplified, goes like this:
enum Container<T> {
case a(T)
case b(T)
case c
}
I want to be able to instantiate this with a few different types for the generic and use typealias for that:
typealias IntContainer = Container<Int>
typealias FloatContainer = Container<Float>
Problem
So far, this is all fine. However, I also want to create a recursive instance of this:
typealias CyclicContainer = Container<CyclicContainer>
Swift reports this with a compile error:
Type alias 'CyclicContainer' references itself
… This error is still reported when I change the Container declaration to:
indirect enum Container<T>
This is a bit annoying, because this would be wholesome and compiling Swift:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
Workaround 1
There is a work around for this. I can declare, for example:
indirect enum CyclicContainer {
case container(Container<CyclicContainer>)
}
… However, this becomes awkward for concise descriptions of a CyclicContainer instance:
let cyclicContainer: CyclicContainer = .container(.a(.container(.b(.container(.c)))))
Instead of just:
let cyclicContainer: CyclicContainer = .a(.b(.c))
Workaround 2
I could also simply create a separate enum for the recursive case, as shown earlier:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
However, I'll need to: create functions to convert between CyclicContainer and Container; re-implement various member functions that exist on Container<T>; and keep the two types in sync in future if I add a new case or change a case name.
This isn't terribly arduous and it's the approach I'm leaning towards. But it seems a shame to have to do this when Swift can handle an indirect enum completely happily, but not when its induced by instantiation of a generic argument on the enum.
Question
Is there a better way?

Swift: Recursive use of generic struct

I'm playing around with linked lists in Swift and I'm using:
struct Node<Element> {
var next: Node<Element>?
}
it yields this error:
Recursive value type "Node<Element>" is not allowed.
I tried using indirect on both the struct declaration and the property but neither worked. How do you implement this type of structure?
When you write var next: Node<Element>?, Swift tries to put this storage inline, but since it's recursive, that results in an infinite-size struct.
indirect only applies to enums, so you could do something like this:
enum Node<Element> {
indirect case Node(Element, next: Node?)
}
Node.Node(42, next: nil)
Or you can use a regular reference type, a.k.a. class:
class Node<Element> {
var next: Node<Element>?
}
It seems that is not possible to create a recursive use of struct, but you can do by using enum, associated values and the indirect attribute.
A recursive enumeration is an enumeration that has another instance of
the enumeration as the associated value for one or more of the
enumeration cases. You indicate that an enumeration case is recursive
by writing indirect before it, which tells the compiler to insert the
necessary layer of indirection.
indirect enum Tree<Element: Comparable> {
case Empty
case Node(Tree<Element>,Element,Tree<Element>)
}
Code taken from AirspeedVelocity.
It's not possible with Structs. It's also doesn't seem wise to do linked list with value types. Unless you feel like doing
head.next.next.next.next.next = head.next.next.next.next.next.next
to delete the seventh node, you're going to want to be able to set
let next = head.next

Swift implicit type conversion between C typedefs

I need to use a third party C library whose source I cannot modify and which makes heavy use of implicit type casting and typedefs to set values for its structs. They are all ints underneath and this is the preferred way of interacting with this library. I've previously used it in Objective C code without issue so now I am mostly porting some of my old code, but it feels like I am constantly hitting a brick wall with Swift.
tl;dr: how can I assign a different typedef value to a C struct member in Swift while automatically handling the type conversions (all typedefs are ints underneath)?
For example, consider the following definitions:
struct library_struct {
int member;
};
typedef enum library_consts {
LIBRARY_DEFINED_VALUE = 0
} library_consts;
In C or Objective C it would be absolutely acceptable to perform the following:
library_struct a;
a.member = LIBRARY_DEFINED_VALUE
However, attempting to do the same thing in Swift
var a: library_struct = library_struct()
a.member = LIBRARY_DEFINED_VALUE
results in an error:
Cannot assign a value of type 'library_consts' to a value of type 'Int32'
I tried several approaches:
Cast using Int32(). This leads to a Cannot find an initializer for type 'Int32' that accepts and argument list of type (library_consts) error.
Use LIBRARY_DEFINED_VALUE.rawValue. This won't work, because rawValue will return an UInt32, so I'm going to get the following error: Cannot assign a value of type 'UInt32' to a value of type 'Int32'
The only alternative is to cast again the value returned by rawValue to an Int32 like this: Int32(LIBRARY_DEFINED_VALUE.rawValue)
This works, but it feels wrong to make a double cast and it doesn't solve more complicated situations such as assigning a value of a different type (but still an int underneath) to a struct member such as the following:
enum library_consts
{
LIB_FALSE=0,
LIB_TRUE=1
};
typedef int lib_bool_t;
typedef struct another_struct {
lib_bool_t aFlag;
}
var b: another_struct = another_struct()
a.aFlag = LIB_FALSE
This will error out with "Cannot assign a value of type 'library_consts' to a value of type 'lib_bool_t'"
I am afraid that there is no easier solution if you cannot change the
C interface. Using the "Generated Interface" view in Xcode 7 you can
see that
enum library_consts
{
LIB_FALSE=0,
LIB_TRUE=1
};
typedef int lib_bool_t;
are mapped to Swift as
struct library_consts : RawRepresentable {
init(_ rawValue: UInt32)
init(rawValue: UInt32)
var rawValue: UInt32
}
typealias lib_bool_t = Int32
(the C int type is Int32 in Swift).
Swift does no implicit type conversions, which means that you have
to convert the types explicitly. In the second case it would be
var b: another_struct = another_struct()
b.aFlag = lib_bool_t(LIB_FALSE.rawValue)

Defining explicit conversion for custom types in Swift

What is currently the best/preferred way to define explicit conversions in Swift? Of the top of my head I can think of two:
Creating custom initializers for the destination type via an extension, like this:
extension String {
init(_ myType: MyType) {
self = "Some Value"
}
}
This way, you could just use String(m) where m is of type MyType to convert m to a string.
Defining toType-Methods in the source type, like this:
class MyType {
func toString() -> String {
return "Some Value"
}
}
This is comparable to Swift's String.toInt(), which returns an Int?. But if this was the definitive way to go I would expect there to be protocols for the basic types for this, like an inversion of the already existing *LiteralConvertible protocols.
Sub-question: None of the two methods allow something like this to compile: let s: MyString = myTypeInstance (as String) (part in parentheses optional), but if I understand right, the as operator is only for downcasting within type hierarchies, is that correct?
The pattern used in swift is the initializer. So for instance when converting an Int to UInt, we have to write:
var i: Int = 10
var u: UInt = UInt(i)
I would stick with that pattern.
As for the subquestion, the documentation states that:
Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy.
and
You can also use type casting to check whether a type conforms to a protocol
so no, the as keyword can`t be used to transform a value of a certain type to another type.
That can be tested in a simple way:
var i: Int = 10
var u: UInt = i as UInt
That generates an error:
'Int' is not convertible to 'UInt'
More about Type Casting