Jump to content

functional programmation error ....


bexphones
 Share

Recommended Posts

hi,

i would use functional programmation but in this case i don't know why it doesn't work.

in first comment code, this works but below and exactly the same it doesn't work..why ?

 

//if(canon[0]){
//	//for (var i = 0; i < canon.length; i++){
//		//game.add.existing(canon[i])
//	//}
//}

function foreach(tableau,action){
	for(var i=0;i<tableau.length;i++){
		action(tableau[i]);
	}
}
		
var logic_add_intenal=function(obj){
	if(obj[0]){
		foreach(obj,game.add.existing)
	}	
}

logic_add_intenal(canon)
// error is TypeError: this.world is undefined

 

Link to comment
Share on other sites

Sounds like a scoping error, i.e. `this` isn't what Phaser is expecting it to be, possibly. I'm not sure why it would be like this though, but scoping often gets tricky (I very rarely refer to `this` so I'm a little rusty on all the rules).

Try adding some logs to see what `this` is (this probably means adding to Phaser's game.add.existing function) in both the commented case and the uncommented. If it is a scoping issue for some reason then binding that function explicitly should resolve it.

Link to comment
Share on other sites

hi mattstyles ;)

Thanks, but always seems to be the same between the 2 functions....honestly i don't see the error.

ps: You say that you rarely refer to this, how do you do to work without him ? in my example how do you do to avoid that ...it's interesting for me to learn. Are you working with prototypes ?

var co=console.log

function foreach(tableau,action){
	for(var i=0;i<tableau.length;i++){
		action(tableau[i]);
	}
}

		
if(dalle[0]){
	for (var i = 0; i < dalle.length; i++){
	                co("dalle",dalle[i])
			co("dalle_game",game)
			co("dalle_this",this)
			game.add.existing(dalle[i])
			}
		}
		var logic_add_intenal=function(obj){
			if(obj[0]){
			     foreach(obj,co)
			     co("obj_game",game)
			     co("dalle_obj",window)
			     foreach(obj,game.add.existing)
			}	
		}
//result : 
dalle Object { name: "dalle", number: 0, image_body: "dalle", image_drag: "sprite_for_drag", posx: 640, posy: 840, flag: true, type: 0, physicsType: 0, position: Object, 52 de plus… }  main.js:1785:5

dalle_game Object { id: 0, config: Object, physicsConfig: undefined, parent: "game", width: 1280, height: 1920, resolution: 1, _width: 1280, _height: 1920, transparent: false, 52 de plus… }  main.js:1786:5

Object { name: "dalle", number: 0, image_body: "dalle", image_drag: "sprite_for_drag", posx: 640, posy: 840, flag: true, type: 0, physicsType: 0, position: Object, 53 de plus… }  util.js:21:3

obj_game Object { id: 0, config: Object, physicsConfig: undefined, parent: "game", width: 1280, height: 1920, resolution: 1, _width: 1280, _height: 1920, transparent: false, 52 de plus… }  main.js:1793:5

TypeError: this.world is undefined[En savoir plus]

 

Link to comment
Share on other sites

Hi @bexphones

I think something like `game.add.existing(dalle).bind(game)` might work (might make it worse! ha ha), but I could be totally and completely wrong. I just seem to remember that I've had a similar problem with a scoped function when its connected to an object/class, can't remember clearly.

9 hours ago, bexphones said:

You say that you rarely refer to this, how do you do to work without him ?

If you're using Phaser (and many many other frameworks) you won't be able to avoid using `this`, its the way the framework works so you have to work that way too.

If you were to redesign the code to not use `this` then you'd probably have to look at what `game.add.existing` does, I'm not sure what it does but lets assume that it adds something to the game, if so then this could just be a simple list add function:

function add (list, item) {
  list.push(item)
  // return list
  // return item
}

Simple right? But that is the point. Pretty much exactly what you've done with your `foreach` function.

If you wanted to get more strictly functional programming about it you'd probably do something like:

const add = list => item => list.push(item)

This is more succinct thanks to the arrow function and by separating the arguments allows you to supply a list and use the new function to add items to it, aiding utility. You could go a step further and use Array.concat to not mutate the list as immutable data goes well with this pattern.

This is a pretty terse example but by splitting things up more and more into functions and breaking them down so that they only operate on their arguments you get to a stage where you rarely create objects with methods so you rarely use `this`, if at all. When you first start splitting things up you end up with functions that require 8 parameters to work, but, just keep going, splitting, reusing, splitting again, and you eventually deconstruct your piece of code into very small functions, when you now look at all those pieces you often work out that only a small part of it relates to the task you're actually doing and this is a good thing because it means all the other stuff can be reused (with ease) somewhere else (see this quote).

It's hardly a silver bullet though and, as with all things, choosing to go Classical and have big objects with loads of methods and object hierarchies and all that jazz is often the easiest thing to do, sometimes going more FP is the easiest thing to do, pros/cons to both in different situations

Link to comment
Share on other sites

Hi, thanks for these explanation. I'm not confortable with const value. Why do you use this ? On the mozilla documentation i understand not yet very well the benefit of this use. i see that your example is a currying function, no?

what is true is that i begin to feel the benefits of the FP, it's cool :). I was scared to always jump between little code to read and understand my code, but it's not the case. 

Your solution works :

		var logic_add_intenal=function(obj){
			if(obj[0]){
				foreach(obj,game.add.existing.bind(game))
			}	
		}

		logic_add_intenal(dalle)

i go to the phaser.js to understand and i understand nothing  :D  In any case not enough to solve my question myself !

have you good reference to learning FP if never  ?

Link to comment
Share on other sites

this don't work :

const add = list => item => list.push(item)
var liste=[100,200]
var ajout=85
add(liste,ajout)
console.log(liste) //100,200

//here it's ok

function added (list, item) {
  list.push(item)
  // return list
  // return item
}
added(liste,ajout)
console.log(liste) //100,200,85

but this ok:

 

Link to comment
Share on other sites

2 hours ago, bexphones said:

I'm not confortable with const value. Why do you use this ?

Sorry, I could have just used var instead, in that case its another way of declaring a function i.e.

const add = list => value => list.push(value)

// is equal to

function add (list) {
  return function addValueToList (value) {
    list.push(value)
  }
}

When using arrow functions you have to assign them to a variable as they are not named. The arrow function value above is just sugar for the bottom way, the old way is actually more powerful as it explicitly names functions which can make debugging easier, plus, its easier to add logs inside the functions should you need more fine-grained debugging. Interestingly, arrow functions have no scope so can not be used with `this`, this is contrary to the popular belief that arrow functions always borrow scope from the surrounding context, which is not true, Kyle Simpson wrote a fantastic article that explains it well here.

2 hours ago, bexphones said:

what is true is that i begin to feel the benefits of the FP, it's cool :) I was scared to always jump between little code to read and understand my code, but it's not the case.

Awesome!

I agree that sometimes what is best is to use functional programming concepts, they can usually be introduced gently so you don't have to jump full-bore into an FP world, if you use frameworks like Phaser or Angular etc etc then you need to stay in the world they define for you, but you can still use functional techniques to help you out.

2 hours ago, bexphones said:

have you good reference to learning FP if never  ?

Some good resources here, many links lead to more links. FP can be very hard to get in to and sometimes blog posts and tutorials can be very harsh on newcomers, its not always the most inviting world which is a great shame.

I strongly recommend Brian Lonsdorf, this book is simply stunning. Lodash/fp is awesome but the docs aren't very helpful for it and not theoretical at all. Libs like Ramda go into explaining some of the functions and concepts a bit better but most FP libs have largely interchangeable functions as FP is heavily based on theory (hence why learning can be tres difficile).

I've recently got in to the Folktale stuff and the Fantasy and Static Land stuff is always great (if a little hard to understand at times!).

Link to comment
Share on other sites

Wouaw fantastic these links ! i read it quicly and it give me the need to print these to read hem carefully. Thanks a lot.

maybe a stupid question, i read in a lot of articles that we need as much as possible use var when we declare a function. however i see that you not. why? what's the reason ?

and just to understand and not to bother you :

5 hours ago, bexphones said:

this don't work :


//here it's not ok
const add = list => item => list.push(item)
var liste=[100,200]
var ajout=85
add(liste,ajout)
console.log(liste) //100,200


//here it's ok
function added (list, item) {
  list.push(item)
  // return list
  // return item
}
added(liste,ajout)
console.log(liste) //100,200,85

 

 

 

Link to comment
Share on other sites

I think they meant 

const add = (list, item) => list.concat(item) 

//example
add([3,4],5)

//output is [3,4,5]

otherwise you have a function that returns a function

and you'd use it like so:

const add = list => item => list.concat(item) 

//example
add([3,4])(5)  

//output is [3,4,5]

(keep in mind that in functional programming you'd rather use `concat` rather than `push` )

Link to comment
Share on other sites

7 hours ago, ldd said:

(keep in mind that in functional programming you'd rather use `concat` rather than `push` )

@bexphones Yep, I toyed with adding that in but left it with a mutable instead. concat returns a new version and hence maintains purity and is generally preferred. It's less useful in the single-arity version of add because of this:

const add = list => item => list.concat(item)

const userList = ['Dave']

const addUser = add(userList)

const addNextUser = addUser('Matt')
console.log(userList) // ['Dave', 'Matt']

const addAnotherUser = addUser('Bex')
console.log(userList) // ['Dave', 'Bex']

This probably isn't what you want, which means that the single-arity stuff isn't as useful for this type of utility.

By using push you actually solve this problem, but, its more dangerous.

14 hours ago, bexphones said:

i read in a lot of articles that we need as much as possible use var when we declare a function. however i see that you not. why? what's the reason ?

You can, I use `var` only when its explicitly necessary, which given that I'm a fan of small functions is hardly ever at all, preferring `const` and `let`, which both help catch a couple of bugs.

The biggest difference between `let` and `var` is how they are scoped, with `let` being a little safer. Function named never get reassigned so `const` makes sense. 

Note that you have to be really careful with `const` as in JS it only applies to the reference, the actual data is NOT constant just because you declared it as so, as you probably know the following could be unexpected:

const list = [1]

list.push(2)

console.log(list)
// [1, 2]

You might expect list to remain [1] for its lifetime (constant) but it does not, all const is doing is ensuring that you can not re-assign `list` by doing something like `list = [1,2,3]`. Same thing is very apparent with objects.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...