A modern language with familiar syntax
ObjoBasic is a statically typed, object-oriented language that reads like English. Everything is an object, types are checked at compile time, and there is no boilerplate to wade through. If you have ever written any BASIC, you will feel right at home.
Clean, Readable Syntax
No semicolons, no curly braces. ObjoBasic reads naturally - declare variables, branch, loop and call methods with plain English keywords. The IDE handles class and method scaffolding for you, so all you write is the logic.
Var greeting As String = "Hello, " + player.Name
Var lives As Integer = 3
If lives > 0 Then
StatusLabel.Text = greeting
StartGame()
Else
StatusLabel.Text = "Game Over"
End If
For i As Integer = 1 To 10
SpawnEnemy(i * 50, 100)
Next i
Everything Is an Object
Integers, doubles, strings, booleans - every value in ObjoBasic is a full object. Call methods directly on literals, chain operations naturally, and never worry about the distinction between primitives and objects.
# Method calls on literals.
Var upper As String = "hello world".Uppercase()
Var hex As String = 255.ToHex()
Var abs As Integer = (-42).Abs()
# Chaining.
Var result As String = " hello ".Trim().Uppercase()
# result = "HELLO"
# Even numbers have useful methods.
Print(7.IsOdd()) # True
Print(100.Clamp(0, 50)) # 50
Print(2.Pow(10)) # 1024
Static Typing Without the Pain
ObjoBasic catches type errors at compile time, not at runtime. Value types like Integer and String can never be Nothing, eliminating an entire category of null-related bugs.
# Explicit types catch errors early.
Var name As String = "Alice"
Var age As Integer = 30
Var scores() As Double = [98.5, 87.3, 92.0]
# Value types are never Nothing.
Var count As Integer # Defaults to 0, not Nothing
Var label As String # Defaults to "", not Nothing
# Type checking at runtime.
If animal IsA Dog Then
Var dog As Dog = Dog(animal)
Print(dog.Breed)
End If
Powerful Collections
Arrays and dictionaries are first-class citizens with literal syntax. Create them inline, access elements by index or key, and iterate with For Each. Dictionaries support any hashable key type.
# Array literals.
Var names() As String = ["Alice", "Bob", "Charlie"]
names.Append("Diana")
names.Sort()
# Dictionary literals.
Var ages As Dictionary(Of String, Integer) = { _
"Alice": 30, "Bob": 25, "Charlie": 35}
# Iterate with For Each.
For Each name As String In names
If ages.HasKey(name) Then
Print(name + " is " + ages.Value(name).ToString())
End If
Next name
Functional Collections
Arrays ship with useful methods like Map(), Where() and Reduce(). Pass inline functions to transform and filter collections in a single expression. Closures capture their surrounding scope automatically.
Var numbers() As Integer = [1, 2, 3, 4, 5]
# Filter.
Var evens() As Integer = numbers.Where(Function(n) n Mod 2 = 0)
# evens = [2, 4]
# Transform.
Var doubled() As Integer = numbers.Map(Function(n) n * 2)
# doubled = [2, 4, 6, 8, 10]
# Accumulate.
Var sum As Integer = numbers.Reduce(0, Function(acc, n) acc + n)
# sum = 15
# Check conditions.
Print(numbers.All(Function(n) n > 0)) # True
Print(numbers.Any(Function(n) n > 4)) # True
Rich String Handling
Strings are immutable, Unicode-aware objects packed with useful methods. String interpolation lets you embed expressions directly.
Var name As String = "Garry"
Var age As Integer = 40
# String interpolation.
Var bio As String = $"My name is {name}, age {age}."
# Useful built-in methods.
Print("hello world".Capitalise()) # "Hello world"
Print("foo:bar:baz".Split(":").Count) # 3
Print(" padded ".Trim()) # "padded"
Print("abcdef".Substring(2, 3)) # "cde"
Print("banana".Replace("na", "🎉"))
# Case-insensitive by default.
Print("Hello" = "hello") # True
Structured Error Handling
Catch errors precisely with Try/Catch/Finally. Match on specific exception types or catch broadly - your choice. The Finally block always runs, making cleanup reliable.
Try
Var data As String = LoadFile(path)
Process(data)
Catch e As FileNotFoundException
Print("Missing: " + e.Message)
Catch e As Exception
Print("Error: " + e.Message)
Throw e # Re-throw if needed.
Finally
Cleanup()
End Try
Events Made Simple
Subscribe to events on any control or object with AddHandler. The IDE creates event stubs for you - just fill in the logic. Multiple handlers can respond to the same event, and you can add or remove them at any time.
# Wire up a button press.
AddHandler btn.Pressed, AddressOf HandlePress
AddHandler btn.Pressed, AddressOf LogPress
# Respond to value changes.
AddHandler slider.ValueChanged, AddressOf OnSliderChanged
# Remove a handler when done.
RemoveHandler btn.Pressed, AddressOf LogPress
# Raise custom events.
RaiseEvent DataLoaded(records.Count)
Async/Await
Write asynchronous code that reads like synchronous code. Await long-running operations and the language handles the rest. Errors propagate naturally through Await, so Try/Catch works exactly as expected.
# Fetch data without blocking the UI.
Var response As HTTPResponse = Await conn.SendAsync( _
"GET", "/api/users")
Var users As String = response.Content
UserList.DataSource = ParseJSON(users)
# Run multiple requests concurrently.
Var tasks() As Task(Of String)
For Each url As String In urls
tasks.Add(conn.FetchAsync(url))
Next url
Var results() As String = Await Task.WhenAll(tasks)
Expressive Control Flow
For/Next with Step, For Each over any collection, While/Wend, Do/Loop with Until or While, and Select Case with multi-value and range matching. Exit and Continue work in every loop type.
# Select Case with multiple matches.
Select Case httpStatus
Case 200
HandleSuccess(response)
Case 301, 302
FollowRedirect(response)
Case Is >= 400
ShowError(response)
End Select
# Loop with early exit.
For Each file As String In files
If file.EndsWith(".tmp") Then Continue
If file.IsBlank() Then Exit
ProcessFile(file)
Next file
Explore the full language reference
Everything you need to know about ObjoBasic — types, classes, generics, error handling, the standard library and more.
Read the full language reference