Type parameters work in a weird way between traits and impl blocks


#1

Hi!

Basically, i wanted to provide an “extension method” for Options that returns true if a provided option is some, so i can use it like this:
let res: Vec<Option<Nucleotide>> = element .to_uppercase() .chars() .map(Nucleotide::parse) .take_while(OptionExtensions::<Nucleotide>::is_some) <-- this is the desired usage .collect();

My first idea was to define a trait with default method, like this:
first try

For this one, i get this error:
type annotations required: cannot resolve _: OptionExtensions<Nucleotide>

I cannot put the type parameter to anywhere where it would work.

However, if i create a “dummy” struct and put the same method to the impl block, like this:
second try

It starts working as intended.

the question is, why? :slight_smile:

thank you


#2

Trait without impl doesn’t do anything. Default methods are only a template, and impl makes them exist.

In this case you don’t need a trait at all. You can use a freestanding function:

fn is_some<T>(opt: &Option<T>) -> bool {opt.is_some()}

https://is.gd/Kgmihz

or even use the existing Option::is_some:

    let b:Vec<bool> = v.iter().map(Option::is_some).collect();

#3

Thank you!

It makes sense. The reason why i started thinking about my own implementation is that i thought i need to pass a “class” method (like in F#, for instance) to make it work.

I thought the library function
fn is_some(&self) -> bool
doesn’t count as a &Option<Nucleotide> -> bool


#4

Just in case you don’t know, Option::is_some() method is already there!

Your example would look like this:

let res: Vec<Option<Nucleotide>> = 
    element
        .to_uppercase()
        .chars()
        .map(Nucleotide::parse)
        .take_while(Option::is_some)
        .collect();