Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add section on inline keyword? #1

Open
isaacabraham opened this issue May 31, 2021 · 4 comments
Open

Add section on inline keyword? #1

isaacabraham opened this issue May 31, 2021 · 4 comments

Comments

@isaacabraham
Copy link

The section that discusses the printByte function mentions (correctly) that F# will infer the input type based on usage, or will fall back to e.g. int.

This time it will refuse to compile, because it has determined that it needs an int and now we've told it to also take a byte type as well. The former input has set the variable input type in stone and it duly refuses

You can actually make the function generic for any type that supports %i by using the inline keyword:

let inline printByte number =
    printfn "%i" number

which creates a function as follows:

val inline printByte :
  number: ^a -> unit
    when  ^a : (byte|int16|int32|int64|sbyte|uint16|uint32|uint64|nativeint|
                unativeint)

Not sure if you want to add this in - but may be useful to know that F# can do this.

@Dhghomon
Copy link
Owner

Thanks, I actually saw this in a video yesterday for the first time and was curious about how it worked - I'll put this in the document too.

One other interesting thing I saw was a static keyword I think that was used to give record types things like the + operator (written with (+) I think) which looks a bit similar to Rust traits (basically you implement a trait for your type and you get all its functions, and then generic functions can take it too because the behaviour is now predictable). Ben Gobeil was showing that in a video.

@Dhghomon
Copy link
Owner

Dhghomon commented May 31, 2021

Okay, here's the addition:

9003678

I am guessing a bit here but it looks like this is the F# version of what we call static dispatch in Rust (which is the more common way to use generics). The compiler does a bit more work up front but then you end up with one concrete function for each type we tell it to call, and that makes it generic from our point of view while also making the runtime fast. (Increases the binary size a tad too)

@isaacabraham
Copy link
Author

One other interesting thing I saw was a static keyword I think that was used to give record types things like the + operator (written with (+) I think)

That's right. F# has some features that use structural typing, rather than nominal, including the (+) operator. So if you have a record or some DU with the static (+) function implemented, you can then do things like Seq.sum on them and it'll call that function.

But this is somewhat unusual in F#, most of .NET is nominal - if you want to do this kind of structural typing stuff in F# you need to start going outside the box using somewhat obscure features in the language like SRTPs - don't go there :-)

@grenaad
Copy link

grenaad commented Dec 30, 2021

I like to think that traits are comparable to a combination of Java/C#'s interfaces and extensions methods. That been said, the static dispatch is basically a constrained on the generic type. While the F# inline does not require to explicitly add this constraint, it is inferred. e.g

let inline add x y = x + y
add 1 2
add "a" "b"
add false "a"  // error: the type string does not match the type bool

The rust equivalent would be to explicitly add the Trait std::ops::Add constrained on the generic types x and y.
It is a small difference, but I think noteworthy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants