Static `super` may cause a unwanted "memory leak".

# /#!/JoePea (8 years ago)

Suppose someone reads about the awesome object-initializer short hand, and writes some code like this:

// How do we create dynamically named functions who's name is guaranteed?
Like this:

let dynamicMethodName = "someMethod"
let tmp = {
    [dynamicMethodName]() {
        // ...
    }
}

let f = tmp[dynamicMethodName]

f.name // someMethod

Little does the unsuspecting author know that the tmp object will be stored as the HomeObject of the created function, therefore it may be considered that some memory has leaked. Suppose an author makes a function factory using that technique,

export default
function SomeFactory(name) {
  let tmp = {
    [name]() { /* this doesn't use `super` */ }
  }
  return tmp[name]
}

Then that will store each new tmp object in memory although the user of the factory only cares about the functions created.

If super were dynamic, tmp would be GCable after it is no longer used in that example, and the object-initializer shorthand method could be treated just the same as any other function as opposed to a special "concise method" (where currently, to me, "concise method" simply means "function that uses static super, otherwise there's no practical difference).

I believe that the object-initializer method shorthand should be syntax sugar, nothing more, so that the following is as equivalent as possible (the only difference being that the function referenced in the following example doesn't have an assigned .name in all JS engines, although Chrome does assign it nowadays):

let dynamicMethodName = "someMethod"
let tmp = {
    [dynamicMethodName]: function () {
        // ...
    }
}

let f = tmp[dynamicMethodName]

f.name // sometimes undefined, "someMethod" in Chrome 51.
# Bergi (8 years ago)

/#!/JoePea schrieb:

export default
function SomeFactory(name) {
  let tmp = {
    [name]() { /* this doesn't use `super` */ }
  }
  return tmp[name]
}

Then that will store each new tmp object in memory although the user of the factory only cares about the functions created.

Why would tmp be stored as the [[HomeObject]] when the function doesn't use super? In that case a [[HomeObject]] is not needed at all.

kind , Bergi

# Jason Orendorff (8 years ago)

On Tue, Aug 2, 2016 at 3:09 PM, Bergi <a.d.bergi at web.de> wrote:

Why would tmp be stored as the [[HomeObject]] when the function doesn't use super? In that case a [[HomeObject]] is not needed at all.

To clarify this: of course the JS engine knows whether the code uses super or not and can decide to retain the [[HomeObject]] only when there's some danger of its actually being needed. But do implementations actually do this optimization in practice?

SpiderMonkey has a findPath() primitive that searches the GC heap for paths from one object to another, handy for answering questions like this one:

js> function SomeFactory(name) {
  let tmp = {
    [name]() { /* this doesn't use `super` */ }
  }
  return findPath(tmp[name], tmp);
}
js> SomeFactory("foo") === undefined
true

That is, there is no GC-path from the method back to the object; apparently [[HomeObject]] is not being retained. What if we change the method to use super?

js> function SomeFactory2(name) {
  let tmp = {
    [name]() { return super[name](); }
  };
  return findPath(tmp[name], tmp);
}
js> typeof SomeFactory2("foo")
"object"
js> SomeFactory2("foo").length
1

Now there is a direct GC-reference from the method to its home object, as expected.

# /#!/JoePea (8 years ago)

Ah, interesting to know. Is such an optimization guaranteed?

# MichaƂ Wadas (8 years ago)

Specification doesn't guarantee any optimization, not even garbage collection, so conforming implementation can allocate objects until OOM.