Crystal: Remove manual symbols in Crystal with automatic casting enums?

Created on 17 Sep 2018  ·  12Comments  ·  Source: crystal-lang/crystal

I'm personally not sure if there are other examples, but #6427 could be easily replaced with an enum listing all the colours instead.

This has several advantages:

  • if a user enters in a wrong colour, the error is a compile-time error, not a runtime error
  • the code for colorize can be much cleaner

However, this might require an overhaul of the entire module since a lot of code in that module is dependent on the symbols themselves - for example, this section of code:

{% for name in COLORS %}
  def {{name.id}}
    @fore = ColorANSI::{{name.camelcase.id}}
    self
  end

  def on_{{name.id}}
    @back = ColorANSI::{{name.camelcase.id}}
    self
  end
{% end %}

As said in the beginning, I'm not sure if there are any other examples of enums being manually duplicated as symbols within the compiler, but if they are I think they should be converted fully to enums as well, to conform with #6074.

Most helpful comment

All the issues with enum shorthands are solved by removing symbols. And enum shorthands are more useful than symbols.

All 12 comments

Bump: any updates?

I think that doing that would help to stress more the the auto casting of symbols to enum feature.

There are some corner cases that were reached in that PR and I think some intents to use the auto caste were reverted.

But I think the main usage of the autcasting for symbols to enum are in method calls, to avoid the user to type. The moment you try to assign it to variable, and pass it around it might do things harder to follow. Because, for example, in the opening comment snippet you might assume @fore is Symbol and not a ColorANSI.

I would personally revert the autocasting feature because it's incomplete (it breaks in the playground) and I can't think of a way to fix that.

@asterite the problem is how the playground instruments code, not in autocasting.

I guess one way to fix it is to stop instrumenting literals (which is anyway not very useful because the value is literally there 😄). Yeah, my comment was a bit too much.

@bcardiff What exactly do you mean by the last paragraph?

I don't know for the removal of automatic casting in general, but at least converting auto-magically from Symbol to Enum is confusing:

  • we don't see any Symbol overload in the API docs, but we can still pass one instead of an enum
  • if we pass a random Symbol, the compiler even tell use we can't use symbols:
Error in line 2: no overload matches 'MyClass.new' with type Symbol
Overloads are: - MyClass.new(num : SomeEnum)
  • this may be a backslash for incremental compilation

@j8r I would have to disagree with some of your points.

For your first point, the fact that there’s no documentation doesn’t matter - symbols are a shorthand in this case, a part of Crystal’s design as opposed to being an overload to a function. Documentation in this case would make more sense in something like the Crystal guidebook.

For your second point, this could be fixed by something like adding an extra section to the error message:

Instead of “:foo”, do you mean:

- :foop (Bar::Foop)
- :foob (Baz::Foob)
- :goo (Quux::Goo)

Another way this could be fixed is by using a special syntax for this type of shorthand, maybe something like :.foo or :foo:, but it’d increase the learning curve and implementation complexity of this feature.

How a beginner is suppposed to know this @Qwerp-Derp ? I find this feature to obfuscate code comprehension: the enum is replaced by a symbol: MyEnum::Val => :val – we lost MyEnum.
This yields to methods accepting symbols instead of an enum.

This feature needs to be documented in the language reference. But only when we're certain about if and how it should stay. Right now, it should be considered experimental, hence the missing documentation. We want to try it out and see how it works while discussing additional features. For example there is a proposal to remove symbols entirely from the language, which would make the current symbol syntax exclusively used to enum autocasts.

@Qwerp-Derp Your idea to improve the error message sounds great. Would you mind opening a separate issue for that?

This yields to methods accepting symbols instead of an enum.

No symbol is ever accepted by this feature. It's only literal symbol syntax that is expanded to the full enum member name when it matches one that fits. It's completely type safe.

this may be a backslash for incremental compilation

There is no difference on the semantic level between Enum::Foo and :foo.

@straight-shoota If I've properly understood, SymbolLiteral could be replaced with a StringLiterral (even CharLiteral) then?

All the issues with enum shorthands are solved by removing symbols. And enum shorthands are more useful than symbols.

Was this page helpful?
0 / 5 - 0 ratings