Those are all dynamic interpreted languages without a strong enforced type system.
Crystal is none of those things.
Take this JSON:
{
"firstName": "John",
"lastName": "Smith",
"isAlive": true,
"age": 27,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
},
{
"type": "mobile",
"number": "123 456-7890"
}
],
"children": [],
"spouse": null
}
The issue is not that crystal doesn’t know that firstName is a String.
Obviously it is and your programm will know it.
BUT if you use data[“firstName”] somewhere in your program and for example want to remove whitespace from the end.
data["firstName"].chomp
what happens if you feed that programm this JSON?
{
"firstName": 4711,
"lastName": "Smith",
"isAlive": true,
"age": 27,
"spouse": null
}
firstName is no longer a string. .chomp nolonger works and you get a runtime error due to a type mismatch.
That is exactly what strongly typed languages will help avoid, and that is also the reason why you need to deal with JSON::Any if you parse unknown JSON and check and do this:
obj = JSON.parse(%({"access": [{"name": "mapping", "speed": "fast"}, {"name": "any", "speed": "slow"}]}))
obj["access"][1]["name"].as_s # => "any"
obj["access"][1]["speed"].as_s # => "slow"
I hope you now better understand the point of Crystal and other strongly typed languages.