Thanks everyone.
@DrScott is correct: if a variable is declared as Stack(Of MyClass), then Pop() should be statically typed as returning MyClass, not Object.
This exposed a compiler bug. Objo understood the generic declaration, but it was losing the concrete type argument when resolving members of user-defined generic classes. Consequently, a return type such as T fell back to Object.
I’ve fixed this for the next release: https://feedback.objo.dev/bug/935
This will now compile without a cast:
Var stack As New Stack(Of MyClass)
Var poppedValue As MyClass = stack.Pop()
The fix wasn’t limited to return values. Concrete generic types are now preserved through constructor parameters, method parameters and return values, properties, inheritance, interfaces, constraints, and iteration. For example, Stack(Of Integer).Push("hello") is now correctly rejected by the compiler.
Objo’s generic classes remain type-erased internally at runtime, but I’ve also added runtime boundary checks so that an incompatible value inserted through an unparameterized generic reference cannot later escape as the wrong concrete type.
In the current release, MyClass(stack.Pop()) is a valid workaround. The second form suggested above, Var poppedValue = ..., is not currently valid because Objo requires an explicit type annotation on local variables.