How to convert global enum values to string in Godot? - enums

The "GlobalScope" class defines many fundamental enums like the Error enum.
I'm trying to produce meaningful logs when an error occurs. However printing a value of type Error only prints the integer, which is not very helpful.
The Godot documentation on enums indicates that looking up the value should work in a dictionary like fashion. However, trying to access Error[error_value] errors with:
The identifier "Error" isn't declared in the current scope.
How can I convert such enum values to string?

In the documentation you referenced, it explains that enums basically just create a bunch of constants:
enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT}
# Is the same as:
const TILE_BRICK = 0
const TILE_FLOOR = 1
const TILE_SPIKE = 2
const TILE_TELEPORT = 3
However, the names of the identifiers of these constants only exist to make it easier for humans to read the code. They are replaced on runtime with something the machine can use, and are inaccessible later. If I want to print an identifier's name, I have to do so manually:
# Manually print TILE_FLOOR's name as a string, then its value.
print("The value of TILE_FLOOR is ", TILE_FLOOR)
So if your goal is to have descriptive error output, you should do so in a similar way, perhaps like so:
if unexpected_bug_found:
# Manually print the error description, then actually return the value.
print("ERR_BUG: There was a unexpected bug!")
return ERR_BUG
Now the relationship with dictionaries is that dictionaries can be made to act like enumerations, not the other way around. Enumerations are limited to be a list of identifiers with integer assignments, which dictionaries can do too. But they can also do other cool things, like have identifiers that are strings, which I believe you may have been thinking of:
const MyDict = {
NORMAL_KEY = 0,
'STRING_KEY' : 1, # uses a colon instead of equals sign
}
func _ready():
print("MyDict.NORMAL_KEY is ", MyDict.NORMAL_KEY) # valid
print("MyDict.STRING_KEY is ", MyDict.STRING_KEY) # valid
print("MyDict[NORMAL_KEY] is ", MyDict[NORMAL_KEY]) # INVALID
print("MyDict['STRING_KEY'] is ", MyDict['STRING_KEY']) # valid
# Dictionary['KEY'] only works if the key is a string.
This is useful in its own way, but even in this scenario, we assume to already have the string matching the identifier name explicitly in hand, meaning we may as well print that string manually as in the first example.

The naive approach I done for me, in a Singleton (in fact in a file that contain a lot of static funcs, referenced by a class_name)
static func get_error(global_error_constant:int) -> String:
var info := Engine.get_version_info()
var version := "%s.%s" % [info.major, info.minor]
var default := ["OK","FAILED","ERR_UNAVAILABLE","ERR_UNCONFIGURED","ERR_UNAUTHORIZED","ERR_PARAMETER_RANGE_ERROR","ERR_OUT_OF_MEMORY","ERR_FILE_NOT_FOUND","ERR_FILE_BAD_DRIVE","ERR_FILE_BAD_PATH","ERR_FILE_NO_PERMISSION","ERR_FILE_ALREADY_IN_USE","ERR_FILE_CANT_OPEN","ERR_FILE_CANT_WRITE","ERR_FILE_CANT_READ","ERR_FILE_UNRECOGNIZED","ERR_FILE_CORRUPT","ERR_FILE_MISSING_DEPENDENCIES","ERR_FILE_EOF","ERR_CANT_OPEN","ERR_CANT_CREATE","ERR_QUERY_FAILED","ERR_ALREADY_IN_USE","ERR_LOCKED","ERR_TIMEOUT","ERR_CANT_CONNECT","ERR_CANT_RESOLVE","ERR_CONNECTION_ERROR","ERR_CANT_ACQUIRE_RESOURCE","ERR_CANT_FORK","ERR_INVALID_DATA","ERR_INVALID_PARAMETER","ERR_ALREADY_EXISTS","ERR_DOES_NOT_EXIST","ERR_DATABASE_CANT_READ","ERR_DATABASE_CANT_WRITE","ERR_COMPILATION_FAILED","ERR_METHOD_NOT_FOUND","ERR_LINK_FAILED","ERR_SCRIPT_FAILED","ERR_CYCLIC_LINK","ERR_INVALID_DECLARATION","ERR_DUPLICATE_SYMBOL","ERR_PARSE_ERROR","ERR_BUSY","ERR_SKIP","ERR_HELP","ERR_BUG","ERR_PRINTER_ON_FIR"]
match version:
"3.4":
return default[global_error_constant]
# Regexp to use on #GlobalScope documentation
# \s+=\s+.+ replace by nothing
# (\w+)\s+ replace by "$1", (with quotes and comma)
printerr("you must check and add %s version in get_error()" % version)
return default[global_error_constant]
So print(MyClass.get_error(err)), or assert(!err, MyClass.get_error(err)) is handy
For non globals I made this, though it was not your question, it is highly related.
It would be useful to be able to access to #GlobalScope and #GDScript, maybe due a memory cost ?
static func get_enum_flags(_class:String, _enum:String, flags:int) -> PoolStringArray:
var ret := PoolStringArray()
var enum_flags := ClassDB.class_get_enum_constants(_class, _enum)
for i in enum_flags.size():
if (1 << i) & flags:
ret.append(enum_flags[i])
return ret
static func get_constant_or_enum(_class:String, number:int, _enum:="") -> String:
if _enum:
return ClassDB.class_get_enum_constants(_class, _enum)[number]
return ClassDB.class_get_integer_constant_list(_class)[number]

Related

Kotlin map not working with List of String

I have been working on code where I have to generate all possible ways to the target string. I am using the below-mentioned code.
Print Statement:
println("---------- How Construct -------")
println("${
window.howConstruct("purple", listOf(
"purp",
"p",
"ur",
"le",
"purpl"
))
}")
Function Call:
fun howConstruct(
target: String,
wordBank: List<String>,
): List<List<String>> {
if (target.isEmpty()) return emptyList()
var result = emptyList<List<String>>()
for (word in wordBank) {
if (target.indexOf(word) == 0) { // Starting with prefix
val substring = target.substring(word.length)
val suffixWays = howConstruct(substring, wordBank)
val targetWays = suffixWays.map { way ->
val a = way.toMutableList().apply {
add(word)
}
a.toList()
}
result = targetWays
}
}
return result
}
Expected Output:-
[['purp','le'],['p','ur','p','le']]
Current Output:-
[]
Your code is almost working; only a couple of small changes are needed to get the required output:
If the target is empty, return listOf(emptyList()) instead of emptyList().
Use add(0, word) instead of add(word).
The first of those changes is the important one. Your function returns a list of matches; and since each match is itself a list of strings, it returns a list of lists of strings. Once your code has matched the entire target and calls itself one last time, it returned an empty list — i.e. no matches — instead of a list containing an empty list — meaning one match with no remaining strings.
The second change simply fixes the order of strings within each match, which was reversed (because it appended the prefix after the returned suffix match).
However, there are many others ways that code could be improved. Rather than list them all individually, it's probably easier to give an alternative version:
fun howConstruct(target: String, wordBank: List<String>
): List<List<String>>
= if (target == "") listOf(emptyList())
else wordBank.filter{ target.endsWith(it) } // Look for suffixes of the target in the word bank
.flatMap { suffix: String ->
howConstruct(target.removeSuffix(suffix), wordBank) // For each, recurse to search the rest
.map{ it + suffix } } // And append the suffix to each match.
That does almost exactly the same as your code, except that it searches from the end of the string — matching suffixes — instead of from the beginning. The result is the same; the main benefit is that it's simpler to append a suffix string to a partial match list (using +) than to prepend a prefix (which is quite messy, as you found).
However, it's a lot more concise, mainly because it uses a functional style — in particular, it uses filter() to determine which words are valid suffixes, and flatMap() to collate the list of matches corresponding to each one recursively, as well as map() to append the suffix to each one (like your code does). That avoids all the business of looping over lists, creating lists, and adding to them. As a result, it doesn't need to deal with mutable lists or variables, avoiding some sources of confusion and error.
I've written it as an expression body (with = instead of { … }) for simplicity. I find that's simpler and clearer for short functions — this one is about the limit, though. It might fit as it an extension function on String, since it's effectively returning a transformation of the string, without any side-effects — though again, that tends to work best on short functions.
There are also several small tweaks. It's a bit simpler — and more efficient — to use startsWith() or endsWith() instead of indexOf(); removePrefix() or removeSuffix() is arguably slightly clearer than substring(); and I find == "" clearer than isEmpty().
(Also, the name howConstruct() doesn't really describe the result very well, but I haven't come up with anything better so far…)
Many of these changes are of course a matter of personal preference, and I'm sure other developers would write it in many other ways! But I hope this has given some ideas.

How to split a string but keep delimiters as separate elements

I have several strings that include various symbols like the following two examples:
z=y+x
#symbol
and I want to split the strings such that I have the resulting slices:
[z = y + x]
[# symbol]
A few things I've looked at and tried:
I've looked at this question but it seems as though golang doesn't support lookarounds.
I know this solution exists using strings.SplitAfter, but I'm looking to have the delimiters as separate elements.
I tried replacing the symbol (e.g. "+") with some variant (e.g. "~+~") and doing a split on the surrounding characters (e.g. "~"), but this solution is far from elegant and runs into problems if I need to do a conditional replacement depending on the symbol (which golang doesn't seem to support either).
Perhaps I've misunderstood some of the previous question and their respective solutions.
I used a modified version of Go's strings.Split implementation https://golang.org/src/strings/strings.go?s=7505:7539#L245
func Test(te *testing.T) {
t := tester.New(te)
t.Assert().Equal(splitCharsInclusive("z=y+x", "=+"), []string{"z", "=", "y", "+", "x"})
t.Assert().Equal(splitCharsInclusive("#symbol", "#"), []string{"", "#", "symbol"})
}
func splitCharsInclusive(s, chars string) (out []string) {
for {
m := strings.IndexAny(s, chars)
if m < 0 {
break
}
out = append(out, s[:m], s[m:m+1])
s = s[m+1:]
}
out = append(out, s)
return
}
This is limited to single characters to split on. And passing something like splitCharsInclusive("(z)(y)(x)", "()") might not get you the output you want, as you'd get a few empty strings in the response. But hopefully this is a good starting point for the modifications you need.
Also, Go's version that I've linked calculates the length of the output array in advance, this is a nice optimization that I've decided to omit, but would likely be good to add back.

Why does _ destroy at the end of statement?

I've seen a few other questions and answers stating that let _ = foo() destroys the result at the end of the statement rather than at scope exit, which is what let _a = foo() does.
I am unable to find any official description of this, nor any rationale for this syntax.
I'm interested in a few inter-twined things:
Is there even a mention of it in the official documentation?
What is the history behind this choice? Is it simply natural fall-out from Rust's binding / destructuring rules? Is it something inherited from another language? Or does it have some other origin?
Is there some use-case this syntax addresses that could not have been achieved using explicit scoping?
Is it simply natural fall-out from Rust's binding / destructuring rules?
Yes. You use _ to indicate that you don't care about a value in a pattern and that it should not be bound in the first place. If a value is never bound to a variable, there's nothing to hold on to the value, so it must be dropped.
All the Places Patterns Can Be Used:
match Arms
Conditional if let Expressions
while let Conditional Loops
for Loops
let Statements
Function Parameters
Is there even a mention of it in the official documentation?
Ignoring an Entire Value with _
Of note is that _ isn't a valid identifier, thus you can't use it as a name:
fn main() {
let _ = 42;
println!("{}", _);
}
error: expected expression, found reserved identifier `_`
--> src/main.rs:3:20
|
3 | println!("{}", _);
| ^ expected expression
achieved using explicit scoping
I suppose you could have gone this route and made expressions doing this just "hang around" until the scope was over, but I don't see any value to it:
let _ = vec![5];
vec![5]; // Equivalent
// Gotta wait for the scope to end to clean these up, or call `drop` explicitly
The only reason that you'd use let _ = foo() is when the function requires that you use its result, and you know that you don't need it. Otherwise, this:
let _ = foo();
is exactly the same as this:
foo();
For example, suppose foo has a signature like this:
fn foo() -> Result<String, ()>;
You will get a warning if you don't use the result, because Result has the #[must_use] attribute. Destructuring and ignoring the result immediately is a concise way of avoiding this warning in cases where you know it's ok, without introducing a new variable that lasts for the full scope.
If you didn't pattern match against the result then the value would be dropped as soon as the foo function returns. It seems reasonable that Rust would behave the same regardless of whether you explicitly said you don't want it or just didn't use it.

Multiple variables of different types in one line in Go (without short variable declaration syntax)

I was wondering if there's a way with Go to declare and initialise multiple variables of different types in one line without using the short declaration syntax :=.
Declaring for example two variables of the same type is possible:
var a, b string = "hello", "world"
Declaring variables of different types with the := syntax is also possible:
c, d, e := 1, 2, "whatever"
This gives me an error instead:
var f int, g string = 1, "test"
Of course I'd like to keep the type otherwise I can just use the := syntax.
Unfortunately I couldn't find any examples so I'm assuming this is just not possible?
If not, anyone knows if there's a plan to introduce such syntax in future releases?
It's possible if you omit the type:
var i, s = 2, "hi"
fmt.Println(i, s)
Output (try it on the Go Playground):
2 hi
Note that the short variable declaration is exactly a shorthand for this:
A short variable declaration uses the syntax:
ShortVarDecl = IdentifierList ":=" ExpressionList .
It is shorthand for a regular variable declaration with initializer expressions but no types:
"var" IdentifierList = ExpressionList .
Without omitting the type it's not possible, because the syntax of the variable declaration is:
VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
(There is only one optional type for an identifier list with an expression list.)
Also I assume you don't count this as 1 line (which otherwise is valid syntax, but gofmt breaks it into multiple lines):
var (i int = 2; s string = "hi")
Also if you only want to be able to explicitly state the types, you may provide them on the right side:
var i, s = int(2), string("hi")
But all in all, just use 2 lines for 2 different types, nothing to lose, readability to win.
This isn't exactly specific to the OP's question, but since it gets to appear in search results for declaring multiple vars in a single line (which isn't possible at the moment). A cleaner way for that is:
var (
n []int
m string
v reflect.Value
)

Overwrite a variable without repeating the name

Is there a method to overwrite variable without copying its name? For example, when I want to change my_var = '3' to an integer, I must do something like this:
my_var = my_var.to_i
Is there way to do this without copying variable's name? I want to do something like this:
my_var = something_const.to_i
For numbers there exists +=, -= etc, but is there universal way to do this for all methods ?
There is no way to covert a string to an integer like that, without repeating the variable name. Methods such as String#upcase! and Array#flatten! work by mutating the object; however, it is not possible to define such a method like String#to_i! because we are converting the object to an instance of a different class.
For example, here is a (failed) attempt to define such a method:
# What I want to be able to do:
# my_var = "123"
# my_var.to_i! # => my_var == 123
class String
def to_i!
replace(Integer(self))
end
end
my_var = "123"
my_var.to_i! # TypeError: no implicit conversion of Fixnum into String
...And even if this code were valid, it would still offer no performance gain since a new object is still being created.
As for your examples of += and -=, these are in fact simply shorthand for:
x += 1
# Is equivalent to:
x = x + 1
So again, there is no performance gain here either; just slightly nicer syntax. A good question to ask is, why doesn't ruby support a ++ operator? If such an operator existed then it would offer performance gain... But I'll let you research for yourself why this is missing from the language.
So to summarise,
is there universal way to do this for all methods?
No. The special operators like +=, -=, |= and &= are all predefined; there is no "generalised" version such as method_name=.
You can also define methods that mutate the object, but only when appropriate. Such methods are usually named with a !, are called "bang-methods", and have a "non-bang" counterpart. On String objects, for example, there is String#capitalize! (and String#capitalize), String#delete! (and String#delete), String#encode! (and String#encode), .... but no String#to_i! for the reasons discussed above.

Resources