# Remove \`{} of Typle\` and \`\[\] of Type\`

**URL:** <https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378>\
**Category:** Crystal Contrib\
**Created:** [February 4, 2019, 12:36pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378 "2019-02-04T12:36:13Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![j8r](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/j8r/32/111_2.png) [@j8r](https://forum.crystal-lang.org/u/j8r)\
**Post date:** [February 4, 2019, 12:36pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/1 "2019-02-04T12:36:13Z")

</div>

There are too much syntax to create an Array or a Hash, it isn’t needed to have 3 ways to do the same thing. This also confuse newcomers, and [experienced ones](https://github.com/crystal-lang/crystal/issues/6980). This isn’t also obvious what is the `of` word (I guess it’s a keyword), a bit too magic.

### Example:

This is the same array:

```auto
p [0, "a"]
p Array(String | Int32){0, "a"}
p [0, "a"] of String | Int32

```

This is the same hash:

```auto
p {"a" => 0}
p Hash(String, Int32){"a" => 0}
# Requires parentheses
p ({"a" => 0} of String => Int32)

```

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [February 5, 2019, 9:53am UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/2 "2019-02-05T09:53:54Z")

</div>

It was discussed before in [https://github.com/crystal-lang/crystal/issues/3399](https://github.com/crystal-lang/crystal/issues/3399)  
Maybe it is time to rediscuss, but for me `[] of String | Int32` looks slightly shorter then `Array(String | Int32).new` and `{} of String => Int32` is definitely easier to understand than `Hash(String, Int32).new`.  
For a nonempty arrays\hashes this syntax is pretty useless though (on the other hand, it could be useful too. You just take existing array literal declaration and add `of T1 | T2...` to it to refine its type).

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [February 5, 2019, 12:42pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/3 "2019-02-05T12:42:59Z")

</div>

I guess we could remove `of` because one can always write it with the longer form. I think `of` is the only infix keyword we have left.

---

<div class="post-metadata">

**Author:** ![bachmarc](https://avatars.discourse-cdn.com/v4/letter/b/8797f3/32.png) [@bachmarc](https://forum.crystal-lang.org/u/bachmarc)\
**Post date:** [February 8, 2019, 3:13pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/4 "2019-02-08T15:13:02Z")

</div>

Maybe this is only because I spend 99% of my coding in ruby:

> Array(String | Int32).new

Is this syn. sugar for a method call of initialize with a Type as parameter?

I would expect something like Array.new(String, 8)

---

<div class="post-metadata">

**Author:** ![girng](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/girng/32/127_2.png) [@girng](https://forum.crystal-lang.org/u/girng)\
**Post date:** [February 9, 2019, 3:21am UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/5 "2019-02-09T03:21:29Z")

</div>

> [@asterite](#):
>
> I guess we could remove `of` because one can always write it with the longer form. I think `of` is the only infix keyword we have left.

“But wait! The [core developers](https://i.gyazo.com/b4be0b61d053b906c292de93b2acf308.png) are not open to change!” - Reddit user #284715 ![](https://yyz2.discourse-cdn.com/flex036/uploads/crystal_lang/original/1X/dcc98fe96b7eb23431dfca982ea235ef77441b72.gif)

---

<div class="post-metadata">

**Author:** ![j8r](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/j8r/32/111_2.png) [@j8r](https://forum.crystal-lang.org/u/j8r)\
**Post date:** [February 9, 2019, 10:32am UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/6 "2019-02-09T10:32:11Z")

</div>

@girng that’s an unrelated issue. This was about missing parentheses with `of`, not to keep/remove them.

This isn’t just about Syntax Sugar, but also about correctness. The `of` syntax hide the fact we instantiate a new generic object `Object(T).new`. The Hash like litteral ([https://crystal-lang.org/reference/syntax\_and\_semantics/literals/hash.html](https://crystal-lang.org/reference/syntax_and_semantics/literals/hash.html)) `{}` uses `[]=` to create initial entries.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://forum.crystal-lang.org/u/Benny)\
**Post date:** [February 11, 2019, 12:25pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/7 "2019-02-11T12:25:26Z")

</div>

This may be slightly offtopic but too much sugar really makes things hard for beginners in Crystal.

Take for instance this:

```auto
class X
  @service_files : {} of String => String

> expecting token 'CONST', not '}'

```

Well, looks correct no? I define the variable as a hash, with String key and String value. Wrong … did not work.

Hmmmm, maybe you need a specific different type.

```auto
class X
   @service_files : Hash( String => String )

> instance variable '@service_files' of Shared::Service was not initialized directly in all of the 'initialize' methods, rendering it nilable. Indirect initialization is not supported.

```

No … more errors. And you keep going down the list of possibilities until you get fed up and write your code to simply auto initialize like this and are left with a bad taste because it just does not feel the correct way of doing it ( especially when you come from different language ).

```auto
class X
    def initialize
        @service_files = {} of String => String    
    end

> Yay, works ... but it feels like a hack rather then the correct way. 

```

It was only until two days ago, when i noticed a piece of code on Gitter, where somebody finally used the ( in my eyes ) correct way of doing it.

```auto
class X

 @service_files : Hash(String, String) = {} of String => String

```

This is frankly way too long and is undocumented. Searched for days trying to find a answer how to properly write this and there was no documented example available.

Good luck on figuring out that this is the way to write this because when you have Hash, {} of, and other ways of writing, it becomes very fast confusing. And yes, i had the answer in my hands all the time but your trying so many different combinations to figure out what, how, why???

I expect to see something

```auto
class X

 @service_files : Hash(String, String) = {} of String => String

```

to work like

```auto
class X

 @service_files : {} of String => String

 @service_files : {"a" => 0} of String => String

```

Trust me when i say that Crystal at times really confuses me as a beginner. PHP has a bunch of gotcha’s but Crystal really makes things confusing.

Well, this also works:

```auto
class X

 @service_files = {} of String => String

```

Slaps hand on head.

So you try:

```auto
class X

 @service_files = Hash( String, String )

> But that does not work

```

They look the same in my eyes but they are not. And the documentation is very, very unclear in this regards, making it impossible to learn by example.

I have no problem figuring out { } of = Hash and [] of = Array but the initialization on a class level was annoying.

PS: Personally i noticed mostly the **{} / [] of** syntax as in my head {} = Hash, [] = Array. As a web developer your used to this pattern more with stuff like Jsons. The syntax is more clean to write.

```auto
{"a" => 0} of String => Int32
Hash(String, Int32){"a" => 0}

```

I dislike the “Hash” version because its less clean to read. Most of my code uses the “of” syntax.  
The fact that {“a” =\> 0} of String =\> Int32 requires parentheses in specific situations looks more like a issue with the Crystal compiler. And yes, it confuses new users also. It needs to be a compiler check or the compiler needs to accept the syntax without the parentheses.

---

<div class="post-metadata">

**Author:** ![bachmarc](https://avatars.discourse-cdn.com/v4/letter/b/8797f3/32.png) [@bachmarc](https://forum.crystal-lang.org/u/bachmarc)\
**Post date:** [February 11, 2019, 3:35pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/8 "2019-02-11T15:35:56Z")

</div>

That is why I asked if all this “char-salad” is syn sugar for @service\_files = Hash.new( String, String ) which would be absolute clear to me.  
This @service\_files = Hash( String, String ) let’s me ask why Hash class does not use a constructor call.  
The colon : ensures I missed something…

=\> In general I really like the ruby like syntax but in detail I am absolutely confused by crystal ways that are somehow unexplained.  
One thing I hate in ruby as well are the 20 ways to write the same that force me to learn foreign ruby-styles more than using the time to understand foreign algorithms and ideas.

---

<div class="post-metadata">

**Author:** ![j8r](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/j8r/32/111_2.png) [@j8r](https://forum.crystal-lang.org/u/j8r)\
**Post date:** [February 18, 2019, 2:05pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/9 "2019-02-18T14:05:19Z")

</div>

There is already `Bytes[1u8, 0u8, 0u8]`, why won’t we have `Array[0, 1, 2]` and `Array(Int32 | String)[0, 1, 2]` too?

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [February 18, 2019, 3:13pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/10 "2019-02-18T15:13:53Z")

</div>

Because you can write `[0, 1, 2]` and `[0, 1, 2] of Int32 | String`…

---

<div class="post-metadata">

**Author:** ![konovod](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/konovod/32/229_2.png) [@konovod](https://forum.crystal-lang.org/u/konovod)\
**Post date:** [February 18, 2019, 5:09pm UTC](https://forum.crystal-lang.org/t/remove-of-typle-and-of-type/378/11 "2019-02-18T17:09:07Z")

</div>

@bachmarc  
`Array(String | Int32)` is a name of type. This is a syntax for a [generic types](https://crystal-lang.org/reference/syntax_and_semantics/generics.html) - types that has compile-time parameters.  
`Array(String | Int32).new` means we are calling `new` method of this type.

Now about `:`.  
Full syntax for a field declaration is `@field : type = value`. You can skip `: type` part though, and compiler will try to deduce type from `= value` part. You can also skip `= value` part, but then you have to initialize a field in `initialize` method. Compiler just have to know what type `@field` has, so he will use any available source to get this information - either `: type` part, or `= value` part, or check of `initialize` methods.

Now to the example with `@service_files`.  
`Hash( String, String )` is a type name, `Hash(String, String).new` or `{} of String => String` are both an expressions that represents empty Hash.  
Full definition well be  
`@service_files : Hash( String, String ) = Hash(String, String).new`.  
You can skip `: Hash( String, String )` part as the type is evident (for a compiler) from the following part.  
So, declaration become `@service_files = Hash(String, String).new`.  
Now you can use a syntax suger to replace it with `@service_files = {} of String => String`. By the way, in this forum thread we are discussing removal of this sugar.

If you instead remove the `= value` part, like so:  
`@service_files : Hash(String, String)`  
The declaration will be correct, but now compiler knows nothing about initial value of field, it knows only it’s type.

Declaration `@service_files = Hash(String, String)` is incorrect because `=` means that we are defining initial value, and `Hash(String, String)` isn’t value, it’s a type name.  
Declaration `@service_files : {} of String => String` is incorrect because `:` means that we are defining type of field, and `{} of String => String` is a shortcut for a `Hash(String, String).new`, it’s a value (empty hash), not a type.

Of course compiler errors about these declarations could be improved, right now they are pretty cryptic. But overall concept of types&values seems pretty simple and evident to me. Documentation could have some improvement too, right now it talks mostly about initialization in an `initialize`, mentions `@field : type` and `@field = value` once and completely skips `@field : type = value` syntax.
