How do we rename types in the standard library properly while following 1.x’s backward compatibility guarantees?
Let’s say a class called Foo
is to be renamed to Bar
. We would do this:
class Bar
end
@[Deprecated]
alias Foo = Bar
Here the deprecation already doesn’t work because aliases don’t support annotations. But even if it works, existing code that relies on Foo
's name might still break. Does the following constitute a breaking change?
x.is_a?(Foo) # okay
x.class.name == "Foo" # breaks after renaming
It can be argued that normal code shouldn’t do the latter anyway, since flow typing is lost. That isn’t the case for AST node types in the macro language though, some of which have been renamed in the past. Suppose Arg
is to be renamed to Param
according to #10374:
{%
node.is_a?(Arg) # okay
node.class_name == "Arg" # breaks after renaming
%}
We could support the former simply by patching Crystal::MacroInterpreter#visit(node : IsA)
to support Arg
as the IsA
's const argument. But what about the latter? My concern is that there isn’t a single Crystal compiler that supports both node.class_name == "Arg"
and node.class_name == "Param"
, so some friction must be present even if the renaming rolls out for 2.0 (contrast this with the recent return
-inside-Proc
semantic changes).