Objects
Object handle syntax
When specifying a type, you mostly need to use the @
symbol to indicate that the type is an object. For example, to declare a variable of type System.Object
, you would use the following syntax:
data obj, @System.Object
The @
can be ignored when declaring a variable of type string
or System.String
and also in some cases related to generic types, but it is otherwise required. For example, the following code is valid:
data str, string
Casting
Casting allows developers to convert one data type into another using the syntax (typename)variable
. This explicit cast is essential when the compiler cannot automatically determine the type conversion or when you intend to treat an instance of one type as another. While this casting method is direct, it can throw an exception if the cast is invalid. To enhance type-checking capabilities, DBL provides the is
and as
operators. The is
operator checks if an object is of a specific type, returning a Boolean result. For example, if (obj .is. SomeType)
would check if obj
is of type SomeType
. On the other hand, ^AS performs a safe cast. It attempts to cast an object to a specified type, and, if the cast isn’t possible, it returns ^null
instead of throwing an exception. For instance, data result = ^as(obj, @SomeType)
would attempt to cast obj
to SomeType
, assigning the result to result
or ^null
if the cast fails. ^AS is only available when compiling for .NET.
Object lifetime
When using Traditional DBL, the lifetime of an object is controlled by keeping a list of all the live roots. This is sort of like reference counting, but it doesn’t have a problem with circular references. Destructors will be called immediately when the last reference to an object goes out of scope. This is different from .NET, where the garbage collector will run at some point in the future and clean up objects that are no longer referenced. Keep this in mind when dealing with objects that have destructors. In .NET, developers will often use the Dispose pattern to clean up resources. When compiling for .NET, DBL offers some syntax support for resource clean-up in the form of the DISPOSABLE
modifier on a DATA statement. It works similarly to using
in C# and will call the Dispose
method on the object when it goes out of scope. For example:
disposable data obj, @MyDisposableObject
Boxing and unboxing
The process of converting value types and descriptor types into objects, and vice versa, is referred to as “boxing” and “unboxing.” These actions are seamlessly handled by the compiler and runtime.
Understanding boxing
Boxing essentially wraps a value type, like an integer or structure, into an object. Declaring a specific-typed box can be done by prepending the typename with @
, like @i
or @my_struct
. For boxing, you can employ either the specific cast syntax (@type)
or a generic (object)
. Depending on the method chosen, the behavior can differ:
- Using
(@type)
cast:obj = (@d)dvar
Remember, when dealing with numeric literals, you must specify if it’s an integer or implied-decimal with (@i4)
or (@id)
respectively.
- Using
(object)
cast:obj = (object)mystructvar
In DBL, boxing takes place automatically under several scenarios, such as
- Passing a literal or value type to a
System.Object
parameter. - Assigning a value type to a
System.Object
variable. - Assigning a literal to a
System.Object
field or property.
When a value gets boxed, it becomes type @System.Object
. This limits its accessibility to only the members of System.Object
.
Understanding unboxing
Unboxing, the counterpart to boxing, extracts the original value from the object. Usually, this involves explicitly casting the object back to its original type. In some scenarios, DBL allows for automatic unboxing, such as when
- Passing a boxed type to a matching unboxed type parameter.
- Assigning a boxed type to a variable with a matching type.
- Accessing a field of a typed boxed structure.
Using (type)
cast:
dval = (d)obj