require "yaml"
class Test
YAML.mapping({
:foo => {type: Hash(Symbol, String), nilable: true}
})
end
pp Test.from_yaml <<-END
foo:
bar: baz
END
In the above code, the YAML parser cannot instantiate the Symbol class because it does not have a new method. Obviously this is deliberate but I wonder if there is a case where the above would be able to work potentially for optimisation sake?
MacOS Sierra Crystal 0.19.1
This will never work, Symbol can't be instantiated dynamically (like in Ruby).
You probably want to use String instead of Symbol.
I figured that might be your response... my only thought here is that isn't this losing the idea of using a symbol? So that you aren't instantiating new strings everywhere?
why we can't intern symbol just like enum from string? seems the same task
Yes, but this is the same in Ruby too. To create a Symbol from a dynamic source you first need to create a String, and then invoke to_sym on it. Of course then the String is garbage-collected and the symbol not, which you might think saves some memory... but then someone can produce memory leaks on your code if they send you arbitrary data and you start caching all kind of symbols. This caused a lot of troubles in well-known Ruby libraries and frameworks, for example Rails. Search "ruby symbol memory leak" in Google, for example this StackOverflow question.
In short, dynamically generating symbols is wrong. In Crystal you can't do this, and we believe this is good.
Also, don't optimize prematurely. You could use a StringPool and maybe use a converter to cache the string into that pool if it turns out that you have a memory bottleneck (but I doubt it).
@kostya We could intern symbols, but then we'd need to somehow garbage-collect unused symbols...
I really think that interning is not needed. And if it is needed, it's maybe better to use an explicit StringPool so that when that pool isn't used anymore the GC can collect it.
(I think Ruby 2.3 fixed this, but it still means more work for the runtime, and maybe it's not worth it)
Ah that makes a lot of sense. I'll let @kostya finish their argument but from my perspective this is pretty much open and close.
Another concern is that string interning involves a global string pool. And we know that global state is bad, specially when you start making things parallel. Both of these are listed as known issues in Wikipedia.
I'm closing this, for now we don't have plans to create symbols dynamically
Most helpful comment
Yes, but this is the same in Ruby too. To create a Symbol from a dynamic source you first need to create a String, and then invoke
to_symon it. Of course then the String is garbage-collected and the symbol not, which you might think saves some memory... but then someone can produce memory leaks on your code if they send you arbitrary data and you start caching all kind of symbols. This caused a lot of troubles in well-known Ruby libraries and frameworks, for example Rails. Search "ruby symbol memory leak" in Google, for example this StackOverflow question.In short, dynamically generating symbols is wrong. In Crystal you can't do this, and we believe this is good.
Also, don't optimize prematurely. You could use a StringPool and maybe use a converter to cache the string into that pool if it turns out that you have a memory bottleneck (but I doubt it).
@kostya We could intern symbols, but then we'd need to somehow garbage-collect unused symbols...
I really think that interning is not needed. And if it is needed, it's maybe better to use an explicit StringPool so that when that pool isn't used anymore the GC can collect it.