Casting problems with large number of types

If I don’t cast type type is Fuse::LowLevel::Request, UInt64, (Fuse::Lib::FuseFileInfo | Int32 | LibC::Stat | Slice(UInt8) | String | UInt64 | Nil), which can’t be passed to the target method because of type restrictions.

If I cast I get the error at the bottom.


case mdata
  # Shouldn't this make mdata available as `{UInt64, String}`?
  when {UInt64, String}
    case name
      when :lookup
        lookup_data ={UInt64, String})


can't cast (
Tuple(UInt64, Fuse::Lib::FuseFileInfo | Int32 | String | UInt64 | Nil) | 
Tuple(UInt64, LibC::Stat | Slice(UInt8) | String | UInt64, Int32 | Int64 | UInt16 | UInt64, Fuse::Lib::FuseFileInfo | String) | 
Tuple(UInt64, String | UInt64, String | UInt16))
to Tuple(UInt64, String)

See src/fuse/ callback_receive_loop
Run using ./test.

You need to do when Tuple(UInt64, String). In your code you are matching against a tuple value, not a tuple type.

If you want to match against a tuple type you need to use a tuple in the case, as explained in (section “Tuple Literal”)

Edit: actually, the “Tuple Literal” stuff is not relevant. {Foo, Bar} is only a tuple type in the type grammar, not in regular code.

If you want to match against a tuple type you need to use a tuple in the case , as explained in (section “Tuple Literal”)

I did follow the book. I don’t see a reference to Tuple(types). Is the book wrong?

Comparing against a type will perform an is_a? check

case {value1, value2}
when {String, Int32}
  # Matches if value1.is_a?(String) && value2.is_a?(Int32)
  # The type of value1 is known to be a String by the compiler,
  # and the type of value2 is known to be an Int32

Using the @def.return_type returns a Tuple() to match against. When I tried the Tuple() syntax (returned from return_type) earlier it matched nothing.

Matching {Int64, String} did match. At runtime it matches.

Sorry, what I said is wrong. But you need to use Tuple(...) to match against a tuple type. Using {...} matches against a tuple value.

Matching {Int64, String} did match. At runtime it matches.

So the value you have is actually a tuple that has Int64 as a type in the first position, and String in the second one? Then using as won’t work. You would need to do as(Tuple(Int64.class, String.class)).

I think the confusion happens because I can’t see all of your code, just an incomplete snippet so I can’t try anything.

I can’t see all of your code, just an incomplete snippet so I can’t try anything.

Link was provided above with a shell script and test case. It’s macro heavy and easier to see the output when the macro fails. Which is what I posted.

Shouldn’t when cast the type for me within scope of the when statement?

case mdata
  when {UInt64, String}
     # mdata is auto cast within this block  

Maybe the nested case statements are throwing the compiler off?

As I said before, if you use when {…} you are not matching against a type but against a value. The compiler only casts when X when X is a type, not a value.

Matching using when Tuple(Int32, Int32) doesn’t work.

Thank you for the code snippet! With it I can finally understand the problem.

I think this is undocumented, but when you mix two tuple types of the same length, for example Tuple(A, B) | Tuple(C, D), the type is turned into Tuple(A | C, B | D). That means that matching against Tuple(A, B) or matching against Tuple(C, D) will never match.

Instead, I recommend not using tuple types and using record to represent the types that you want.

My advice is to avoid tuples and named tuples as much as possible.


case mdata
  when {UInt64, String}
    lookup_data =, String.class))
#                       ^ as
    lookup(req, parent_ino: lookup_data[0], name: lookup_data[1])

def lookup(req : Request, parent_ino : UInt64, name : String) : Nil


Error: no overload matches 'Fuse::MidLevel::Handler#lookup' with types

 Fuse::LowLevel::Request, parent_ino: UInt64.class, name: String.class

I’ll give record/struct a try.

My other solution would make a channel with fibers for each data type. Most apps would need nproc to max_net_connecions Fibers. I don’t know if 8-20 * ncpu fibers with dedicated type channels is faster or a single pool of ncpu fibers inside of a giant case statement.