Primtive types
The base types for expressing values in UltraGen
In this article we'll discuss the types used for coding your applications in UltraGen. The base types are Integer, Float, Byte, String, Null, Boolean.
Variables of these types are always accessed by value. At this time you can't define explicitly a mode to access variables. Primitive always by value. Composed types always by reference.
Numeric
Numeric values are held by the self explanatory Integer, Float and Byte types. The byte type holds an integer between 0 and 255. In fact, when using it, the number has the same behavior of an integer.
Float holds a real number. Internally it's a floating point number with 80-bit precision (the extended FreePascal data type).
Integer holds any operation result that returns an Integer number. Even if a float is involved in operation. If the return is an integer number, the result is an integer.
All numeric types can be mixed in an operation.
String
The type for storing textual data. Strings are stored as a raw byte stream. That said, the correct output will depend from the viewer expected encoded. Anyway, built-in functions which relies on text match are based on UTF-8 and may fail when using non-ASCII characters. For these cases you can use the ByteStream and handle raw bytes very easily.
Literal strings may be enclosed in single or double quotes if they are on same line. You can declare a multiline string using triple quotes. Single quote doesn't need to be escaped inside double quoted literal and vice-versa. Neither single or double quotes need to be escaped.
sq = 'this can have " without problems"
dq = "this can have ' and it's ok"
tq = """this can even
use a newline
inside the string"""
The character \
can be used to escape some character. Some escape combinations produces special features in string.
Combination | Produces |
---|---|
\n | newline |
\t | tab |
\r | carriage return |
When writing strings that are Windows paths you must double the slashes.
path = "my\windows\path.exe"
# wrong: the string will be "mywindowspath.exe"
path = "my\\windows\\path.exe"
# this is right
However, the most recommended is to use the path
method from List type to handle file paths.
path = ['my', 'windows', 'path.exe'].path()
idStrings
There is a syntax sugar for strings that are valid names. They are the idStrings. They are ordinary strings and support all of its methods. The only difference is that they written with a colon followed by a name.
x = :aName
print (typeof(x))
# will print "String"
This form exists for better semantics in cases where an argument is a string but a form that seems like an identifier is better readable. Let's take a look at this snippet which shows a Router handler definition. Don't matter about the router. Focus at concept.
These definitions require a route, a name for that endpoint and a function as arguments.
# the second arg must be a string
router.get('/some/path', 'myRoute', handler)
# now written in idString syntax
router.get('/some/path', :myRoute, handler)
In the first form, "myRoute" seems like it could be any literal value. In fact it is but in this context "myRoute" is an identifier of a route. So the idString syntax make this more evident by dropping the quotes.
In your script, you can use this name to reverse return a route with router.urlFor(:myRoute)
. It's visible that :myRoute
looks much more like an identifier than "myRoute"
. Another good case of use is to define or access dictionary keys which presents the same semantics. In the next snippet we're getting hypothetical information from a user as JSON and the fields are name, username, age.
resp = Request.get("/user/someone")
user = JSON.parse(resp.text)
print(user[:name])
print(user[:age])
print (user[:age])
Again we made the fields look like identifiers with this simples syntax change.
That said, when you're in a case like that, use idStrings.
Boolean
Boolean is the type for representing boolean values. They can be only true
or false
. The most important thing to talk about this type is to show its "truthy" and "falsy" values. This definition is used in if
and while
evaluations.
Truthy and falsy values
In an if
or while
condition, some non-boolean values are taken as true or false so you can write a little less. We call this conventions truthy and falsy
Are truthy:
- Any string with length greater than zero.
- Numerics greater than 0
- A list with length greater than 0
- A non-empty dictionary
- Any object except
null
Are falsy:
- An empty string
- Numerics less than or equal 0
- A list with 0 length
- An empty dictionary
- The
null
object.
Remember that you can't compare different types. So, even though an empty string is evaluated as false
you can't make a "" == false
comparison. It will return a type error and advice that you can't compare different types. If you need something like this, type cast the value with bool
. It uses the same rules to evaluate a value as true or false.
NullType
This is the type for holding the null
object. Internally it's not a null pointer reference. Even null
is an object internally in UltraGen. So, set some variable to null
does not "dereference" it. It just sets a variable to a value that has no specific value. It's like the var
declaration in some languages just for initialize some variable. Consider that such statement does not exist in UltraGen. A variable must be initialized with a value. If you don't have one but you need the name to exist, use null
.
One step forward
In the next chapter we will talk about the composed types. This mean types who are composed by other but are also core types from UltraGen.