The Crystal Programming Language Forum

Post-1.0 aliases in the standard library

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).

I suppose you could do something like:

abstract TmpBar
# some common old Bar code
end

module OldBar
# some old Bar code
end

module NewFoo
# some old Foo code
end

@[Deprecated]
class Bar < TmpBar
  include OldBar
end

class Foo < TmpBar
  include NewFoo
end

Seems kinda hacky, and there might be no diff’s needed (yet); but maybe it’ll help w/ refactoring later.

There is no refactoring involved; Bar and Foo should refer to exactly the same type, otherwise code that does x.is_a?(Foo) will immediately break as soon as other methods in the standard library refer to Bar.

Oops; I had Foo and Bar mixed up.

I suppose this won’t suffice either?:

class Bar
# old Foo code goes here
end

@[Deprecated]
class Foo < Bar
end