Skip to content

get_slice behavior is inconsistent and error prone when the string contains no matching delimiter #107726

Open
@FeldrinH

Description

@FeldrinH

Tested versions

  • Reproducible in: 4.4.stable.official, 4.3.stable.official

System information

N/A

Issue description

String.get_slice returns the entire original string when delimiter does not occur in the string. This behavior is inconsistent and can cause a number of subtle and confusing bugs in user code.

I propose that this special case when the delimiter is not found is effectively a bug and should be removed. Instead, get_slice should follow the general rule when the delimiter is not found (i.e. return the entire string if slice == 0, otherwise return the empty string).

Steps to reproduce

Consider the following examples that illustrate issues that this behavior can cause:

A simple function that returns the third element from a comma separated list:

func third_element(values):
    return values.get_slice(",", 2)

This produces the following output:

third_element("0,1,2,3") == "2" # correct
third_element("0,1,2") == "2" # correct
third_element("0,1") == "" # correct
third_element("0") == "0" # incorrect, the first element shows up as the third element

A simple function that extracts and concatenates the first and third element:

func extract_pair(values):
    values.get_slice(",", 0) + "," + values.get_slice(",", 2)

This produces the following output:

extract_pair("0,1,2,3") == "0,2" # correct
extract_pair("0,1,2") == "0,2" # correct
extract_pair("0,1") == "0," # correct
extract_pair("0") == "0,0" # incorrect, the first element unexpectedly appears to be the third element as well

In addition, the current behavior breaks the intuitive expectation that get_slice is equivalent to split followed by getting the respective element or empty string if there is no such element:

func get_slice(value, delimiter, slice):
    var parts = value.split(delimiter)
    return parts[slice] if slice < len(parts) else ""

This produces the following output:

"0,1,2,3".get_slice(",", 2) == get_slice("0,1,2,3", ",", 2) == "2" # matches
"0,1,2".get_slice(",", 2) == get_slice("0,1,2", ",", 2) == "2" # matches
"0,1".get_slice(",", 2) == get_slice("0,1", ",", 2) == "" # matches
"0".get_slice(",", 2) != get_slice("0", ",", 2) # does not match (built-in get_slice returns "0", while the split-based implementation returns "")

Minimal reproduction project (MRP)

N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions