The Crystal Programming Language Forum

Does autocasting enums for default parameter work for alias unions?

enum Auto
  Auto
end

def cell(width : Auto = :auto)
  pp width.class
end

cell()

this works fine. calling cell shows the type is Auto
But if I use a alias union Width of Int32 and Auto instead

enum Auto
  Auto
end

alias Width = Int32 | Auto

def cell(width : Width = :auto)
  pp width.class
end

cell()

I get this error


 219 | def cell(width : Width = :auto)
                ^
Error: can't restrict Symbol to Width

As your example shows, it seems to not work for unions. That might be problematic when a union contains different enum types with conflicting members, or just plain symbols.

You can use different overloads though. For calling cell this is equivalent to the union type restriction.

enum Auto
  Auto
end

def cell(width : Auto = :auto)
  pp width.class
end

def cell(width : Int32)
  pp width.class
end

cell()
1 Like

Are there plans to make this work? It feels right that auto casting should work given declare the type to be Width.

by the way I can usually work around this problem by being explicit.

enum WidthOption
   Auto
end

alias Width = Int32 | WidthOption

def cell(width : Width = WidhtOption::Auto)
  pp width.class
end

cell()

This works. I just think the syntax for symbols currently is causing quiet a bit of inconsistency in Crystal.

Interestingly, autocasting works at callsite:

enum WidthOption
   Auto
end

alias Width = Int32 | WidthOption
 
def cell(width : Width)
  pp width.class
end

cell(:auto)

It’s just broken for the default argument.

Unfortunately, this is true. Autocasting is a great feature but it only works to some extent. It’s not too bad I think. But eventually, I’d like to remove the symbol datatype so symbol literals can be used exclusively for enum members, which would help improve some use cases for that. But there’s no progress on that and it may actually be harder than it seems.

1 Like

Note that this works already:

enum Auto
  Auto
end

alias Width = Int32 | Auto

def cell(width : Width)
  pp width.class
end

cell(:auto)

It just doesn’t work when you use it as a default value inside the method, and that’s a bug. I’ll try to fix today.

If I don’t get to fixing it, the workaround is very simple: use Auto::Auto in the default value, but that still allows passing :auto in the method, which I think is the important part you were looking for?

1 Like

Yes at call site it works. Which is how I got it working in the library so far. But it’s good to know that not working as default value is considered a bug.

Fixed! https://github.com/crystal-lang/crystal/pull/9366 :-)

2 Likes

That’s crazy fast!! Thanks @asterite