A number of existing languages do allow this and there is no particular issue with it. Java permits it for reference types, for example, as do C# and Scala:
Foo Bar = new Foo();
Bar Foo = new Bar();
This code is accepted, and works without issue and generally without ambiguity.
There is one ambiguous construct this creates in the Java model: ordinarily, Foo.meth()
calls the static method meth
on the Foo
class, but now it will attempt to dispatch on the variable instead and either fail or find an unrelated method from type Bar
. A different language could distinguish instance and static method access syntactically and not face this issue, or simply not have them, or not overload the name of the type with the name of the class.
Many languages have no meaningful dynamic existence of types (or associated entities) at all, and these would generally not have even the opportunity for a run-time issue to arise. These are not forced to disambiguate at all.
Strictly speaking, this is also doable in a number of functional languages with algebraic data types and first-class functions. For example, in the Haskell code
data Foo = Foo Int
x = Foo
the second Foo
is in the value namespace, holding a function from Int
to Foo
. Both type and function do remain available in their contexts as usual. However, this variable can't have any other value than that, so it may not meet the spirit of the question.
There's then no particular semantic problem with allowing this, and certainly nothing that rules it out entirely.
As well as these semantic issues, there can be syntactic ones: C famously has context-dependent lexing due to typedefs already, and generally requires feeding names of declared types into the lexer so that it can disambiguate (A)*B
as a cast or multiplication. Given int int = 10
, (int)*x
would be terminally ambiguous.
It would be possible to constrain the syntax rules so this can't be written, in this case for example by requiring that the pointer dereference be written (*x)
, but it is a deeper change. Similar issues might arise in other languages that would otherwise benefit from a clear distinction between type and variable names.
From a language-design perspective, having types (or classes, constructors, ...) as first-class values in a shared namespace is quite fundamental, and a language that did not allow it would be very different. This is a choice that the language is making, probably deliberately. For example, first-class values for these may be used for dependency injection, higher-order programming, or pattern matching, and core to the ergonomics of the language.
All in all, allowing this is within the range of choices available to the language designer. There are tradeoffs involved in that, and it may be incompatible with other, more important features, but certainly not ruled out entirely if different choices are made.