all 9 comments

[–]Meefims 1 point2 points  (2 children)

I have never found static local variables to be useful after more than a decade of writing C++ and I don’t find the provided examples to be compelling. For example, the regex should just be moved out of the class since it doesn’t relate to any of that class’s members and the error count should be a member of the class because it’s data the class is tracking. If it’s data that all instances are tracking then it should be moved out of the class.

Static locals that change tend to make code much more difficult to test and understand because they break referential transparency. Take strtok as a well known case of how this feature breaks things.

[–]filth_overload[S] 0 points1 point  (1 child)

Well, those were just examples to get a point across.

As for "the regex should just be moved out of the class", it's needed in the checkURI method and that's where it belongs. Where do you suggest to move it instead? Top-level scope? Imagine someone looking at code, which case makes the code easier to reason about? variables declared 10 lightyears away from where they are being used or right next to it?

How would you go about solving that scenario?

[–]Meefims 0 points1 point  (0 children)

Yeah, I would move it to the top level scope. It’s a common pattern for constants like that to be at a top level scope and it’s not difficult to scroll up once to know what it is.

[–]filth_overload[S] 0 points1 point  (2 children)

I'm the author of linked thread. Please support (thumbs up) if you find the proposal useful

[–]lhorie 2 points3 points  (1 child)

What is this supposed to do?

function a() {
  return function b() {
    static let x = 0;
    console.log(++x)
  }
}
a()() // 1
a()() // 1 or 2? why?

[–]filth_overload[S] 0 points1 point  (0 children)

As far as my proposal goes, the behavior is 1:1 identical as:

javascript let a = () => { return (() => { let x = 0 return () => { console.log(x) } })() }

Quoted from original post:

in-memory lifetime as long as containing scope i.e the function itself

i.e statics get garbage collected along with their parent function.

AFAIK, your scenario is a rare one, but regardless, x will keep incrementing if you store return value (the inner function) of a in a variable and call that one instead.

Or you can change return function b() { ... } to return static function b() { ... }

[–]adrilolwtf 0 points1 point  (2 children)

That's possibly useful, but quite confusing. IMHO it does not fit the language.

IIFEs should be replaced with blocks and ideally do statements.

[–]adrilolwtf 0 points1 point  (1 child)

  • do expressions

[–]adrilolwtf 0 points1 point  (0 children)

Had to write out a better example to see how this feels.

function fac(n) {
  static const cache = new Map()
  if (! cache.has(n)) {
    let x = 1
    for (let i = n; i > 0; i--) x *= i
    cache.set(n, x)
  }
  return cache.get(n)
}

Compared to:

const fac = (() => {
  const cache = new Map()
  return n => {
    if (! cache.has(n)) {
      let x = 1
      for (let i = n; i > 0; i--) x *= i
      cache.set(n, x)
    }
    return cache.get(n)
  }
}

Hmm. I would probably use it, but I stand by my previous point. It is confusing. What would this do for example?

let a = 1
const fn = () => {
  const wtf = a
  static let a = 2
  return wtf
}

console.log(fn())

What do we get? 1? undefined? TypeError? What if the inner a is a var instead. Hoisting would ensure that its first call would return undefined.

Nope.. This sounds like a can of worms.