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

Problem with Array[String val] contains using result of string.substring #2759

Closed
sirscratchalot opened this issue Jun 7, 2018 · 8 comments

Comments

@sirscratchalot
Copy link

Hello, I've hit a wall with Array.contains when calling with the result of a String.substring operation.
This returns false even when equivalent calls using equivalent strings return true.

Here is a quick code example with printouts as comments, the unexpected behaviour comes in the final print statement :

actor Main 
  new create(env: Env) =>

    let imageEndings:Array[String val] val = [".jpg";".png";".bmp";".gif"]
    env.out.print("String in Array "+imageEndings.contains(".png").string())
    //Prints: String in Array true
    let endPng:String val = ".png"
    env.out.print("Let in Array "+imageEndings.contains(".png").string())
    //Prints: Let in Array true
    let imageName ="testing.png"
    let size=imageName.size().isize()
    let ending:String val = recover val imageName.substring(size-4, size).lower() end
    env.out.print("Ending "+ending.clone()+" "+ending.size().isize().string()+" "+imageEndings.contains(ending).string())
    //BUT, this prints: Ending .png 4 false
    //What's going on with substring?

Expected behaviour would be a final print out of:

Ending .png 4 true

Originally brought this up on the freenode chat and was asked to create an issue for this. Hopefully I interpreted this correctly and came to the right place.

@EpicEric
Copy link
Contributor

EpicEric commented Jun 7, 2018

By default, the Array.contains function receives a second parameter, predicate, which is a lambda for comparison of elements.

The default value is a lambda that does identity comparison (i.e. l is r), while in this case you would expect a structural comparison (i.e. l == r).

In your case, you can provide a custom lambda for structural equality in your code:

let predicate': {(String val, String val): Bool} = {(l: String val, r: String val): Bool => l == r })
imageEndings.contains(ending where predicate = predicate').string()

The fact that the first two calls to Array.contains appear to work as you expected are more likely due to compilation optimizations, so that the same pointer is used in memory for the ".png" string in all the first three instances. The ending variable is created on runtime, meaning it will always have a different identity.

Personally, considering how identity comparison should work, the first two calls to Array.contains should also have returned false, since the val alias is not being shared explicitly in the code.

@SeanTAllen
Copy link
Member

I'm going to call this a bug. However, its a documentation bug,

Array.contains should explain the predicate. It should explain that "matching" is done based on identity and it should give examples of how to do something like what @sirscratchalot wanted to do.

@winksaville
Copy link
Contributor

Would following be considered good pony form? The types of l and r are inferred and not having the "where" clause?

actor Main

  new create(env: Env) =>
    let imageEndings:Array[String val] val = [".jpg";".png";".bmp";".gif"]
    let endSubStr:String val = ".png".substring(0, 4)
    let resultEndSubStr=imageEndings.contains(endSubStr, {(l, r): Bool => l == r})
    env.out.print("resultEndSubStr=" + resultEndSubStr.string())
    // Prints ResultEndSubStr=true

@SeanTAllen
Copy link
Member

other than the "not standard library" formatting, yes, that is how you would want to use contains in this situation @winksaville.

@winksaville
Copy link
Contributor

From the style guide for lambda it looks like I need to add a space before the trailing brace to make it standard, anything else?

let resultEndSubStr=imageEndings.contains(endSubStr, {(l, r): Bool => l == r })

@SeanTAllen
Copy link
Member

space before and after the =.

snake case for variables.

@winksaville
Copy link
Contributor

Txs, so:

let result_end_sub_str = image_endings.contains(end_sub_str, {(l, r): Bool => l == r })

@SeanTAllen
Copy link
Member

yup

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

4 participants