Search code examples
genericstypescastingtype-conversioncrystal-lang

Generic type convertion


I am trying to create a method which gets input from the user and converts that to a specified type. Is there a way to do this without rewriting for each type.

Something like this:

struct Input(InputType)
    def self.get_from_stdin(msg_fail : String = "Error! Wrong type, please reenter: ")
        input = gets
        begin
            input = input.to_s.to(InputType)
        rescue
            puts msg_fail
            input = Input(InputType).get_from_stdin
        end
        input
    end
end

age = Input(Int32).get_from_stdin("Age must be a number, please reenter: ")

Basically, I want to achieve something akin to this:

foo = foo.to(MyType)

I imagine this would be difficult to do without macros.


Solution

  • Instead of messing with generics or macros I would look into ways to reduce boilerplate. That is extract common code into a yielding method and then write specific methods for each case you want to handle on top of that.

    def prompt_user(prompt)
      print prompt
      print ' '
      loop do
        input = gets
        if input && !input.strip.empty?
          break yield input
        else
          print "Please enter a value: "
        end
      rescue
        print "Wrong type, please reenter: "
      end
    end
    
    def prompt_int32(prompt)
      prompt_user(prompt, &.to_i32)
    end
    
    def prompt_my_thing(prompt)
      prompt_user(prompt) {|value| MyThing.parse value }
    end