Name rules and conflicts
The Hybrix language allows you to reuse the same name for different definitions. Consider the identifier button in the code below:
class button
end class
class page
# This member variable "self.button" has type "class button":
var button: button
func initialize()
# This local variable "button" also has type "class button":
var button: button
# In "new button()", the word "button" is naming the class constructor.
new button() -> button
# Assign the local variable "button" to the "self.button" member
button -> .button
end func
end class
How many things can be called "button" before the compiler reports a naming conflict? The rules below answer this question.
Name scopes
The Hybrix language defines name scopes. If two definitions belong to the same scope, they cannot have the same name.
| Name scope | Example of declaration in this scope |
|---|---|
| Names of modules | module example |
| Names of types | type example class example primitive types ( int, byte[], etc.) |
| Namespace members (accessed using ::) | var inside a moduleconst inside a module or class*func inside a module or class* |
| Instance members (accessed using .) | var inside a classfunc inside a class |
| Func parameters and locals | var example inside a func bodyfunc example() |
* Most class members are accessed using ., however constants and member function pointers aren't associated with any particular instance.
If the same name is reused within the same scope, the compiler reports an error:
Conflict: names of modules
module m
end module
# ⚠️ ERROR: There is already a module named "m"
module m
end module
Conflict: names of types
type t is int
# ⚠️ ERROR: There is already a type named "t"
class t
end class
Conflict: namespace members
module m
var v: int
# ⚠️ ERROR: There is already a module member named "v"
func v()
end func
end module
Conflict: class members
class my_base
var f: int
end class
class my_child extends my_base
# ⚠️ ERROR: There is already a class member named "f"
func f()
end func
end class
Note that a child class inherits members from its base class, and these names share a single scope.
Conflict: func parameters and locals
module m
func f(p: int)
# ⚠️ ERROR: There is already a parameter named "p"
var p: int
end func
end module
Name qualifiers
It's generally okay to reuse the same name in different name scopes. The Hybrix language syntax uses explicit qualifiers such as :: and . to distinguish scopes, which prevents any ambiguity about what a name is referring to.
| Name scope | Example syntaxes referencing this scope |
|---|---|
| Names of modules | module_name::x |
| Names of types | var v: type_name v as type_name |
| Namespace members | my_module::member_name |
| Instance members | my_object.member_name .member_name |
| Func parameters and locals | var_name without any prefix |
Counterparts
When a top-level type has the same name as a module, we call them counterparts. There are two possibilities: type alias and module counterparts, and class and module counterparts.
Note that type alias and class counterparts are not allowed, because class and type definitions both belong to the same name scope.
Type alias and module
The example below shows type alias and module counterparts named vector:
type vector is int[size 3]
module vector
func get_length_squared(vector: vector): int
return vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]
end func
end module
module main
func start()
var vector: vector
new int[size 3]() -> vector
var result: int
result <- vector::get_length_squared(vector)
end func
end module
Important points:
- The module members are accessed using
::as usual, for examplevector::get_length_squared(). - The
typealias simply coexists alongside themodule.
Class and module
The example below shows class and module counterparts named cat:
class animal
var name: string
constructor(name: string)
.name <- name
end constructor
end class
class cat extends animal
func meow()
end func
end class
module cat
var best_cat: cat
func init()
cat::best_cat <- new cat("Mittens")
end func
end module
Important points:
- The module members are accessed using
::as usual, for examplecat::best_cat. - The class's object members are accessed using
., for example.name. - The
moduleandclassmust not reuse the same name for any member. This includes inherited members.
Continuing the above example, defining module cat like this would produce an error:
module cat
var best_cat: cat
func init()
cat::best_cat <- new cat("Mittens")
end func
# ⚠️ ERROR: The class already has a member called "name" (inherited from animal)
func name()
end func
end module
Keeping the rules simple
When we say a
moduleandclassmust not reuse the same name for any member, that policy is stricter than technically necessary. Consider this example:class counterparts_example
var x: int # some_instance.x
end class
module counterparts_example
# ⚠️ Disallowed only because it would be confusing
var x: int # counterparts_example::x
end moduleThere is actually no confusion between these two
xvariables; we can always distinguish them by::versus., and if you think carefully you can find even more interesting examples:class c
const y is 123 # c::y
# ⚠️ Disallowed only because it would be confusing
var y: int # some_instance.y
end classThe language treats these as naming conflicts for two reasons:
- It's difficult to explain when it would be allowed (for example, function pointer syntax puts class member functions into both the namespace scope and instance scope).
- It's not particularly useful. Your code will be easier to read without this kind of name reuse.