# Why Crystal allows reassigning a variable with a different type

**URL:** <https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551>\
**Category:** Crystal Contrib\
**Created:** [March 16, 2019, 12:20pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551 "2019-03-16T12:20:14Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![avitkauskas](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/avitkauskas/32/3186_2.png) [@avitkauskas](https://forum.crystal-lang.org/u/avitkauskas)\
**Post date:** [March 16, 2019, 12:20pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/1 "2019-03-16T12:20:14Z")

</div>

As for the strict typed language, I find it strange that Crystal allows to reassign the variable with a different type. I would expect that after the type of the variable was infered from it’s usage, assigning a different type value to that variable in the same scope would produce an error.

This works fine and is concidered a feature of the language:

```crystal
x = 1
x = "str"

```

If you explicitly define a type of the variable, you cannot reassign it a different type value (like it’s expected in a strict typed language):

```crystal
x : Int32
x = 1
x = "str" # Error: type must be Int32, not (Int32 | String)

```

But that does not work with the method parameters:

```crystal
def method(x : Int32)
  # I would expect this produce an error, but it's not
  x = "str"
end

method(0) # "str" : String

```

Allowing to redefine the variable if the type was infered from the default value could be expected to be consistent with this feature of the language:

```crystal
def method(x = 0)
  x = "str"
end

```

**Summarising:**

- Why strict typed language allows to reassign the variable with the different type if the type was infered from the first usage?
- Why it allows to reassign the method parameter with a different type value even it it was explicitly typed in the definition of the method?

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [March 16, 2019, 1:15pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/2 "2019-03-16T13:15:33Z")

</div>

One of Crystal’s features is that method arguments and local variables do not need to be explicitly typed.

The issue you’re seeing is more so because you are totally overriding the variable. `x` used to be an `Int32` on line 1, but is now a `String` on line 2 because there wasn’t an explicit type guard saying what that local var should be.

The method example is similar, you have a type guard on a method that only allows that type, but would not prevent you totally overriding it in the method body. Adding a return type to the method would be one way to ensure the method returns what you are expecting. That example would also not work with instance vars as those always have to have a type.

---

<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:** [March 16, 2019, 2:33pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/3 "2019-03-16T14:33:20Z")

</div>

Redefining is sometimes useful and also makes code more compatible with ruby:

```crystal
def login(user : String, id : String)
  user = Users.find(user)
  id = id.to_i? || new_id
  ...

```

or

```crystal
node = first
while node # node can be nil
  node.process
  node = node.next #oops, item has type Node, not (Node | Nil)
end

```

etc.

Also this won’t prevent errors “user declared another variable with same name” - because user can still declare another variable but with same type.

---

<div class="post-metadata">

**Author:** ![avitkauskas](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/avitkauskas/32/3186_2.png) [@avitkauskas](https://forum.crystal-lang.org/u/avitkauskas)\
**Post date:** [March 16, 2019, 3:16pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/4 "2019-03-16T15:16:51Z")

</div>

I think compatibility with Ruby should not be an argument: Crystal is Crystal, not Ruby - it only “borrows” a very nice syntax of Ruby, but it should adapt it the way it fits the strict typed language.

My concern is this: I expect that stictly typed language saves me from unexpected change of the type of my variables. And Crystal (because of this allowed variable redefinition) does not ensure this.

**Example:**

This works fine

```crystal
def push(a : Array(Int), v : Int32)
  a << v
end

a = [0]
a = push(a, 1) #=> [0, 1]

```

But if I make a mistake (use = instead of \<\< in my method), my method wrongly returns an Int32 instead of Array(Int32), but compiler is still happy about that:

```crystal
def push(a : Array(Int), v : Int32)
  a = v # intended to write a << v
end

a = [0]
# No error
a = push(a, 1) #=> 1

```

And somewhere further in the code I will be surprised that `a` is not an array any more.

Of course, I could restrict the type of the variable by explicitly typing it:

```crystal
def push(a : Array(Int), v : Int32)
  a = v # intended to write a << v
end

a : Array(Int32) # this saves me
a = [0]
a = push(a, 1) #=> Error: type must be Array(Int32), not (Array(Int32) | Int32)

```

But that urges you to always use explicit typing and the very idea of Crystal beeing smart to infer the types from the first usage of the variables then becomes obsolete.

I love Crystal being smart and requiring very little explicit type declarations, and that’s why I think it should not allow so easily to redefine the variables if their type was infered from the fist usage.

@konovod, I see your point in redefinition beeing useful sometimes, but I would rather not allow it in the strict typed language and would write your code like I put it below (but would feel more assured that compiler helps me if I accidentaly did something not intended):

```crystal
def login(user_name : String, user_id : String)
  user = Users.find(user_name)
  id = user_id.to_i? || new_id
  ...

```

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [March 16, 2019, 3:20pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/5 "2019-03-16T15:20:01Z")

</div>

You’re problem here could be solved by just adding a return type to your `push` method.

[https://play.crystal-lang.org/#/r/6ice](https://play.crystal-lang.org/#/r/6ice)

---

<div class="post-metadata">

**Author:** ![avitkauskas](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/avitkauskas/32/3186_2.png) [@avitkauskas](https://forum.crystal-lang.org/u/avitkauskas)\
**Post date:** [March 16, 2019, 3:21pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/6 "2019-03-16T15:21:50Z")

</div>

Sure, but this again means that if you want to be safe, then you must always be explicit about all the types. And that is not what Crystal phylosophy of being smart to infer implicitly is about.

---

<div class="post-metadata">

**Author:** ![Blacksmoke16](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/blacksmoke16/32/1241_2.png) [@Blacksmoke16](https://forum.crystal-lang.org/u/Blacksmoke16)\
**Post date:** [March 16, 2019, 3:30pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/7 "2019-03-16T15:30:43Z")

</div>

This is a feature of the language. Method args and variables do not _have_ to be explicitly typed; but they can be if you want it to be of a specific type.

Of course this is only an issue for local variables, instance vars _have_ to be typed and are able to have their type inferred.

You’ll just have to explicitly type your local vars which you can do inline btw `a : Array(Int32) = [0]`, or use a class/struct which would provide guaranteed type safety.

---

<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:** [March 16, 2019, 3:45pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/8 "2019-03-16T15:45:03Z")

</div>

The safety of the language comes from the compiler preventing to invoke an undefined method on an object. Type restrictions are just there for a bit more clarity and for overloads. They are not there for type safety.

---

<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:** [March 16, 2019, 3:45pm UTC](https://forum.crystal-lang.org/t/why-crystal-allows-reassigning-a-variable-with-a-different-type/551/9 "2019-03-16T15:45:41Z")

</div>

As you mentioned in your example, if you do a=v you’ll get a compile time error later on. The safety remains.
