question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[closures] Concept examples and explanation needs improvements

See original GitHub issue

Hi. While I was learning concepts for JavaScript I found out that closures theory isn’t very helpful for solving the suggested practical exercise: Coordinate Transformation.

I would like to propose to improve it by

  • adding a more advanced example with an explanation for using a function in return
  • explain how to work with its arguments then.

Let me know what do you think. Connected links are here: https://exercism.org/tracks/javascript/concepts/closures https://exercism.org/tracks/javascript/exercises/coordinate-transformation

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:3
  • Comments:14 (14 by maintainers)

github_iconTop GitHub Comments

4reactions
SleeplessBytecommented, Nov 29, 2021

Sooooo. 👋🏽

Definitions are as difficult as naming is (I wrote articles about similar subjects in the past, for example: JavaScript, Ruby, and C are not call by reference), which is what makes this even more interesting. Yes, in general closures are often defined as enclosing values inside a function, which is often possible in languages that “do not treat functions as a special case” (meaning functions are first-class citizen, and can be passed around, just like other values). This is usually mentioned because if you can pass functions around, it means you can often execute the function on a completely different call site then where it was defined. The operational bonus is then that that function has access to variables it had access to when it was defined despite the call site NOT (necessarily) being able to access those.

Okay. Great.

In JavaScript blocks (the first example) cannot be passed around, but in some other language (hello there Ruby), some forms of blocks are callable (effectively making them similar or the same as functions), ánd can be passed around.

Because the block from the example is static/fixed in place, its power to enclose the variable is “lost”. It doesn’t matter. Therefore I would agree to bin the example, despite you probably being able to find references where a writer argues that any enclosure is “a closure”. I’m not willing to say that we absolutely cannot call this a closure, but in general, when people who know JavaScript or similar languages talk about closures, they will almost always refer to instances of functions that enclosed variables, and thus not talk about blocks.

TL;DR; correctness of the first example doesn’t matter. It’s use-case is basically none (other than creating a new block which can be great when writing switch statements and their cases. I would vote to remove it.


✨ Everything that follows is just extra information and should not be included in this exercise

Are there other ways to enclose other than using a function?

Yes! For example classes can do this too.

const definedOutside = 'hello, world!'

export class Shout { 
  // This function is technically a closure
  call() { console.log(definedOutside); }
  
  // This variable is, once this proposal becomes language,
  // technically enclosing a value from outside this class, but will
  // probably not be called a closure
  #privateVar = definedOutside
}

const utterance = new Shout()

utterance
// => Shout {#privateVar: 'hello, world!'}

utterance.#privateVar
// => SyntaxError Private field '#privateVar' must be declared in an enclosing class

utterance['#privateVar']
// => undefined

utterance.call()
// => 'hello, world!'

Classes can in fact enclose values passed from the outside in their constructor, variables created in their constructor, or even variables attached to themselves

export class Enclosing {
  constructor(passedValue) { 
    let increment = 0
    
    this.magicNumber = 21
    const self = this;
     
    // Return a new object that does NOT have Enclosing as its prototype

    return {
      // encloses variable defined in constructor
      increase() { 
        increment += 1
        return increment;
      },
      
      // encloses variable passed in constructor
      call() { console.log(passedValue); },

      // encloses the entire object that was created by the constructor
      ref() { return self.magicNumber * 2 }
    }
  }
}

// Now try it out
const enclosed = new Enclosing('Goodbye, Mars!')

enclosed.magicNumber
// => undefined

enclosed.increase()
// => 1

enclosed.call()
// => "Goodbye, Mars!"

enclosed.ref()
// => 42
2reactions
SnowJambicommented, Feb 5, 2022

+1 on this. I’m doing this exercise for the first time, and I had no idea what I was being asked to do, and I couldn’t manage to glean much context from the test cases either.

I haven’t finished it yet, but particularly task 1 seems to be lacking information for someone who has never encountered this before.

Intuitively, if I were to write the translate2d function myself, I would write something like

function translate2d([x, y], [dx, dy]) {
  return [x + dx, y + dy]
}

let coords = [1, 2]
console.log(translate2d(coords, [2, 3])
// [3, 5]

Ok, cool, but now looking at the task 1 information

const moveCoordinatesRight2Px = translate2d(2, 0);
const result = moveCoordinatesRight2Px(4, 8);
// result => [6, 8]

My first thought is how on earth does the arguments from moveCoordinatesRight2Px get passed in to translate2d? This is something that hasn’t been seen so far in the learning track, and it’s dropped on us with no explanation apart from stating that translate2d should return a function.

It wasn’t until I somehow just happened to stumble upon the answer, that I was able to work backwards from there and understand what is happening.

function translate2d(dx,dy) {
  return function translate(x, y) {
    return [x + dx, y + dy]
  }
}

console.log(translate2d(2,3))
// function translate(x, y) { return [x + dx, y + dy]; }
// ^ Aha!
// From that...
console.log(translate2d(2,3)(1,1))
// [3,4]

I’m not sure if I accidentally missed a lesson before this one or if I’m just not the brightest around, but some more information would be extremely useful, maybe as @Jasstkn mentioned an example of returning a function to give the user some more guidance towards the solution, because as it is, I’m pretty sure if I didn’t have some prior experience and this was my first time learning I would be hard stuck here for sure.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Closures - JavaScript - MDN Web Docs
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
Read more >
9 Wrap Up Activities for Lesson Closure That Work Like a Charm
Closing a lesson well helps students retain information and helps you ... they understood the concept or a rating of personal improvements.
Read more >
7 Steps to Nail the Project Management Closure Process
Go through your project plan to identify all deliverables and make sure they have been fully completed and handed off. 2. Confirm project...
Read more >
Defining Closure Psychology - BetterHelp
Consider the following example: Sean breaks up with Amy via a text message. Amy perceived that everything was going well and is completely ......
Read more >
Project Closing Phase - UMass Boston
Project Closing Phase · Measures how closely the project met customer needs · Identifies what worked well on the project and what needs...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found