# Some question(or improvement?) for Crystal

**URL:** <https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618>\
**Category:** Crystal Contrib\
**Created:** [May 11, 2022, 3:41pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618 "2022-05-11T15:41:39Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)\
**Post date:** [May 11, 2022, 3:41pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/1 "2022-05-11T15:41:39Z")

</div>

Don’t know if appropriate create this thread here, anyway, i am quite newbie for crystal, and still learning, following is some confusing things(and maybe improvement advice) for now.

* * *

1. i consider following code should not a valid syntax.

```crystal
# a blank space added between new with left parenthesis
SomeClass.new ("String") # this is bad, i propose this is a invalid syntax.

SomeClass.new("String") # this is good

```

Anyway, unified format is better (as go), we don’t want to write another `rubocop` for crystal, just for change those bad syntax habit, right?

* * *

1. getter :name, should not accept symbol as argument, we prefer to use only one form(as python) to do same things, right?

```crystal
getter :name # => bad

getter name # => good

```

* * *

1. What the `Int` in the method parameter type stand for?

```crystal

# following code just work
def fact(n : Int) : Int32
  p typeof(n)
  if n < 0
    puts "n must be positive!"
    exit
  end
  n == 0 ? 1 : n * fact(n - 1)
end

# But follow declare not work.
x : Int; # => can't use Int as the type of variable yet, use a more specific type

```

i am so curious, why we can use Int as a `alias` for Int32 in parameter, but, can not use  
it for declare, and in fact, change to following code not work too.

```crystal
def fact(n : Int) : Int
  p typeof(n)
  if n < 0
    puts "n must be positive!"
    exit
  end
  n == 0 ? 1 : n * fact(n - 1) # no overload matches 'Int32#*' with type Int

```

* * *

1. This more like a question, for curious, what is the real type of the tuple key? why we can visit the value correctly use both String or Symbol?

```crystal
foo = {aaa: 100} # => what is the key type?

p foo["aaa"] # => 100
p foo[:aaa] # => 100

```

* * *

1. because `crystal run "$@"` is the default of `crystal "$@"`,

e.g.

```nohighlight
$: crystal run test.cr
$: crystal test.cr # same as above

```

There is almost no arguments supported when use crystal without sub command, except -h and -v, so, can we pass all arguments of `crystal run --??` to `crystal --??`?

e.g.

```nohighlight
$: crystal run test.cr --error-trace # this work
$: crystal test.cr --error-trace # this not work, --error-trace was ignored
Showing last frame. Use --error-trace for full trace.
...
Error ...

```

Thank you.

---

<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:** [May 11, 2022, 4:01pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/2 "2022-05-11T16:01:48Z")

</div>

> [@zw963](#):
>
> 1. i consider following code should not a valid syntax.

I’m not sure I would go as far as to make that invalid syntax. They get parsed/ran exactly the same. Plus running the formatter (`crystal tool format`) removes the empty space so we already have a unified format as enforced by the formatter.

> [@zw963](#):
>
> 1. getter :name, should not accept symbol as argument, we prefer to use only one form(as python) to do same things, right?

I think this is just a product of how the macro works. E.g. you can do `getter foo, :bar, "baz"` and all of them generate the same thing. I don’t really see that form of it used too often as most people do like `getter name : String` versus a list or untyped getter. Could make that more strict, but debatable what the benefit would be, plus would need to wait until 2.0 anyway? 🤷

> [@zw963](#):
>
> 1. What the `Int` in the method parameter type stand for?

`Int` would be [Int - Crystal 1.10.1](https://crystal-lang.org/api/Int.html). I.e. the base type of all integer types. When used as a method parameter restriction, it allows _any_ int type. There’s also number autocasting now so like even if you did `def foo(id : Int64)` you could still do `foo 10` and `10` just gets automatically converted to an `Int64`.

The error you get is just a limitation of the compiler at the moment where it prevents you from using certain types to restrict a local or ivar. E.g. you can’t do `getter id : Int` either. Don’t recall if there’s an issue for this, or any plans to allow it.

> [@zw963](#):
>
> 1. This more like a question, for curious, what is the real type of the tuple key? why we can visit the value correctly use both String or Symbol?

NamedTuples have a key type of `Symbol`. But the API allows accessing the value by both the `String` and `Symbol` representation. I.e. are overloads for each type, but internally the keys are always `Symbol`.

> [@zw963](#):
>
> 1. because `crystal run "$@"` is the default of `crystal "$@"` ,

IIRC the difference is that when using `run` the arguments are passed to the the compiler while when not using it, they’re passed to the program. In order to pass args to the program you need to add them after `--`. For example:

```auto
crystal run test.cr --error-trace # --error-trace flag is passed to the compiler
crystal run test.cr --error-trace -- --foo # --error-trace flag is passed to the compiler, --foo flag passed to program
crystal --foo --error-trace. # Both flags are passed to the program

```

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 11, 2022, 5:00pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/3 "2022-05-11T17:00:02Z")

</div>

Regarding `getter` and similar macros: Yeah, I think it would make sense to restrict the allowed argument types. Maybe there is already some rule in ameba, not sure.  
It’s really just that implementation is based on `{{ argument.id}}` which makes a lot of things work. Even some really weird things like `getter ::foo()`, for example 🤷  
I would definitely that that’s not well-formatted. Perhaps the formatter could apply some corrections. At least ameba should (if not already). And maybe in 2.0 we could actually restrict the allowed types for arguments.  
I think it should always be `Var` to match `Assign` for declarations with value.

---

<div class="post-metadata">

**Author:** ![zw963](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/zw963/32/1623_2.png) [@zw963](https://forum.crystal-lang.org/u/zw963)\
**Post date:** [May 11, 2022, 5:01pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/4 "2022-05-11T17:01:14Z")

</div>

> [@Blacksmoke16](#):
>
> I’m not sure I would go as far as to make that invalid syntax. They get parsed/ran exactly the same. Plus running the formatter ( `crystal tool format` ) removes the empty space so we already have a unified format as enforced by the formatter.

I propose do this, Crystal still not use so widely, we have chance to fix it anyway,  
following is reason.

1. use formatter is optional, this encourage bad code style
2. It may cause issue, at least, maybe write not clear code, following is a example.

```crystal
def foo(arg1)
  p arg1
end

arg1 = "String"

# what is the argument passed to foo? true or 7?
foo (arg1.responds_to? :size) && arg1.size + 1

# is this same as above?
foo(arg1.responds_to? :size) && arg1.size + 1

```

If we don’t permit add space between, we can always clear, all part of `(arg1.responds_to? :size) && arg1.size + 1` is argument.

anyway, i consider do this change for Crystal is not a big deal, because most of developer use formatter, right?

---

<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:** [May 11, 2022, 6:02pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/5 "2022-05-11T18:02:34Z")

</div>

> [@zw963](#):
>
> ```auto
> getter name # => good
> 
> ```

That won’t work if you want a getter called `end` or `begin`, because those are keywords. That’s the main reason why we also let symbols here.

---

<div class="post-metadata">

**Author:** ![jwoertink](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jwoertink/32/50_2.png) [@jwoertink](https://forum.crystal-lang.org/u/jwoertink)\
**Post date:** [May 12, 2022, 3:15pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/6 "2022-05-12T15:15:30Z")

</div>

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

🤪

macros be crazy lol

---

<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:** [May 12, 2022, 3:18pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/7 "2022-05-12T15:18:13Z")

</div>

FWIW this works the same as if you just defined the methods directly. I.e. It doesn’t work _just_ because you used the `getter` macro:

```auto
class Foo
  def end
    "hmm"
  end
    
  def begin
    "yup"
  end
end

```

---

<div class="post-metadata">

**Author:** ![jwoertink](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jwoertink/32/50_2.png) [@jwoertink](https://forum.crystal-lang.org/u/jwoertink)\
**Post date:** [May 12, 2022, 3:29pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/8 "2022-05-12T15:29:21Z")

</div>

crystal be crazy lol

---

<div class="post-metadata">

**Author:** ![HertzDevil](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hertzdevil/32/1023_2.png) [@HertzDevil](https://forum.crystal-lang.org/u/HertzDevil)\
**Post date:** [May 12, 2022, 5:44pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/9 "2022-05-12T17:44:04Z")

</div>

By the way, `getter begin` is invalid syntax, but `getter begin : B` is valid. [In fact `Range` does exactly that](https://github.com/crystal-lang/crystal/blob/81a0d5df5f3a2e4a32bd11d3680e7d8d5b229e7a/src/range.cr#L63-L77). `Regex::MatchData` also defines `#begin` and `#end`.

```crystal
def fact(n : Int) : Int
  n == 0 ? 1 : n * fact(n - 1)
end

fact(5) # Error: no overload matches 'Int32#*' with type Int

```

I am not so sure if this should fail. The return value restriction never types the actual returned value, only that the value’s type is a subtype of `Int`, so `fact(n - 1)` shouldn’t be typed to the abstract struct `Int` here. This may be a nuance in the type inference algorithm when it comes to recursive methods, though.

---

<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:** [May 12, 2022, 8:52pm UTC](https://forum.crystal-lang.org/t/some-question-or-improvement-for-crystal/4618/10 "2022-05-12T20:52:47Z")

</div>

@HertzDevil Oh, good point. At one point we added a rule that if a recursive method couldn’t be typed right away, try to use the return type. But it seems that introduced the bug that you mention.
