Skip to content

bug: nameref += append to indexed array doesn't work #804

@chaliy

Description

@chaliy

Problem

When using local -n (nameref) to reference an indexed array, the +=("value") append operator silently does nothing. The caller's array remains empty.

Scalar assignment through nameref works. Associative array key assignment through nameref works. Only indexed array append via += is broken.

Reproduction

append_via_ref() {
  local -n ref="$1"
  ref+=("x")
  ref+=("y")
}

target=()
append_via_ref target
echo "${#target[@]}"   # Expected: 2, Actual: 0
echo "${target[*]}"    # Expected: x y, Actual: (empty)

Impact

wedow/harness uses this exact pattern to collect plugin ordering:

# bin/harness — _collect_hooks_from()
_collect_hooks_from() {
  local dir="$1"
  local -n map_ref="$2"      # → associative array (works)
  local -n order_ref="$3"    # → indexed array (BROKEN)
  for f in "${dir}"/*; do
    [[ -x "${f}" ]] || continue
    local base="$(basename "${f}")"
    map_ref["${base}"]="${f}"   # ✓ works
    order_ref+=("${base}")      # ✗ broken — append lost
  done
}

What works vs what doesn't

# ✓ Direct array append
arr=()
arr+=("a")
echo "${#arr[@]}"  # → 1

# ✓ Nameref scalar assignment
set_val() { local -n r="$1"; r="hello"; }
x=""; set_val x; echo "${x}"  # → hello

# ✓ Nameref assoc array key assignment
set_key() { local -n r="$1"; r["k"]="v"; }
declare -A m; set_key m; echo "${m[k]}"  # → v

# ✗ Nameref indexed array append
append() { local -n r="$1"; r+=("item"); }
a=(); append a; echo "${#a[@]}"  # → 0 (expected 1)

Test cases

# Basic append through nameref
pusher() {
  local -n ref="$1"
  ref+=("alpha")
  ref+=("beta")
  ref+=("gamma")
}
items=()
pusher items
echo "${#items[@]}"
# Expected: 3

echo "${items[0]} ${items[1]} ${items[2]}"
# Expected: alpha beta gamma

# Append to non-empty array
starter=(existing)
pusher starter
echo "${#starter[@]}"
# Expected: 4

echo "${starter[0]}"
# Expected: existing

# Index assignment through nameref (should also work)
set_index() {
  local -n ref="$1"
  ref[0]="first"
  ref[1]="second"
}
arr2=()
set_index arr2
echo "${arr2[0]} ${arr2[1]}"
# Expected: first second

# Multiple namerefs — one assoc, one indexed (harness pattern)
collect() {
  local -n map_ref="$1"
  local -n order_ref="$2"
  map_ref["a"]="/path/a"
  order_ref+=("a")
  map_ref["b"]="/path/b"
  order_ref+=("b")
}
declare -A mymap
myorder=()
collect mymap myorder
echo "${mymap[a]}"      # Expected: /path/a
echo "${myorder[0]}"    # Expected: a
echo "${#myorder[@]}"   # Expected: 2

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions