Categories
discuss

Three.js error –> THREE.Scene is not a constructor

I can’t execute my code because of this error:

TypeError: THREE.Scene is not a constructor

I use the three.js file from the official github repo and here are my files:

index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../style.css">
    <title>First three.js</title>
</head>
<body>
    <script type="module" src="../frontend/tetrahedrons_render.js"></script>
</body>
</html>

tetrahedrons_render.js

import * as THREE from '../lib/three.js';
// Create the scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x2d3436);
// Set up the camera
const camera = new THREE.PerspectiveCamera(100, window.innerWidth / window.innerHeight, 0.1, 1000);
// Set up the render
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
// Create n random tetrahedrons
const n = Math.floor(Math.random() * 7) + 2;
const tetrahedrons = [];
const positions = [];
let x, y;
for (let i = 0; i < n; i++) {
  do {
    x = Math.floor(Math.random() * 10) - 5;
    y = Math.floor(Math.random() * 10) - 5;
  } while ([x, y] in positions);
  positions.push([x, y]);
  tetrahedrons.push(createTetrahedron(x * 2.5, y * 2.5));
}
// Color one random tetrahedron in black and another in white
const i = Math.floor(Math.random() * tetrahedrons.length);
let i2;
do {
  i2 = Math.floor(Math.random() * tetrahedrons.length);
} while (i2 === i);
tetrahedrons[i].geometry.faces.forEach((face) => {
  face.color = new THREE.Color('black');
});
tetrahedrons[i2].geometry.faces.forEach((face) => {
  face.color = new THREE.Color('white');
});

camera.position.z = 15;

function animate() {
  requestAnimationFrame(animate);
  // Rotation
  tetrahedrons.forEach((tetrahedron) => {
    tetrahedron.rotation.x += 0.03;
    tetrahedron.rotation.y -= 0.03;
  });
  renderer.render(scene, camera);
}
animate();

function createTetrahedron(x, y) {
  const geometry = new THREE.Geometry();
  geometry.colorsNeedUpdate = true;
  geometry.vertices.push(
    new THREE.Vector3(1, 1, 1),
    new THREE.Vector3(-1, -1, 1),
    new THREE.Vector3(-1, 1, -1),
    new THREE.Vector3(1, -1, -1),
  );
  // * To be pointing toward the outside of the cube
  // * they must be specified in a counter clockwise
  // * direction when that triangle is facing the camera
  geometry.faces.push(
    new THREE.Face3(0, 2, 1),
    new THREE.Face3(0, 3, 2),
    new THREE.Face3(0, 1, 3),
    new THREE.Face3(1, 2, 3),
  );
  // Set faces colors
  geometry.faces[0].color = new THREE.Color('red');
  geometry.faces[1].color = new THREE.Color('blue');
  geometry.faces[2].color = new THREE.Color('green');
  geometry.faces[3].color = new THREE.Color('yellow');
  // Set materials
  const material = new THREE.MeshBasicMaterial({
    color: 0x95a5a6,
    vertexColors: THREE.FaceColors,
  });
  material.needsUpdate = true;
  const tetrahedron = new THREE.Mesh(geometry, material);
  tetrahedron.geometry.colorsNeedUpdate = true;
  // Add the tetrahedron to the scene
  scene.add(tetrahedron);
  tetrahedron.position.x = x;
  tetrahedron.position.y = y;
  return tetrahedron;
}

Here’s the all code, but I think the problem must be at the first line import.

I saw a lot of posts with a similar error but I can’t find a solution for me.

Answer

Three.js has three output files:

  • three.js
    • An un-mangled bundle of the three.js source
  • three.min.js
    • A mangled/minified (smaller) version of the bundled three.js source
  • three.module.js
    • A JavaScript module version of the three.js bundle

You need to reference the last one in order to import the three.js exports. Copy three.module.js into your lib folder, then:

import * as THREE from '../lib/three.module.js';
Categories
discuss

Kotlin Coroutines – Thread Switching

I am new to Android Coroutines. I’ve been reading about it from the official docs and found this note

Important: Using a dispatcher that uses a thread pool like
Dispatchers.IO or Dispatchers.Default does not guarantee that the
block executes on the same thread from top to bottom. In some
situations, Kotlin coroutines might move execution to another thread
after a suspend-and-resume. This means thread-local variables might
not point to the same value for the entire withContext() block.

but I didn’t get this specific sentence

This means thread-local variables might
not point to the same value for the entire withContext() block

Can anyone show me an example of this scenario?

Answer

myLooper() and prepare() on Looper use a thread-local variable for holding a per-thread Looper instance.

So, imagine this scenario:

  • You launch() a coroutine on Dispatchers.Default
  • In that coroutine, you prepare() a Looper and try using that for something (e.g., with a Messenger)
  • You then call some suspend function

When that suspend function returns, you may not be on the same thread as you were on before calling that suspend function. It will be a thread from Dispatchers.Default, but not necessarily the specific thread you were on before. As a result, your Looper might be associated with some other thread, one that you’re fighting with the coroutines system to use. Depending on what you were trying to do here, the fact that you are on a different thread might cause problems in what you wanted the Looper for.

The real lesson here is: use HandlerThread to get a Looper, rather than prepare().

Categories
discuss

ant design v4 breaks react testing library tests for Select and Autocomplete

I have recently upgraded my React project to ant design v4 and all the tests that use a Select, AutoComplete or Tooltip are broken. Basically when clicking the components, the modal or select options are not present in JSDOM. This used to work fine in v3.

Can somebody show me how to test antd v4 with react testing library ?

Example:

My Component:

import React from "react";
import "./styles.css";
import { Select } from "antd";

const { Option } = Select;

function handleChange(value) {
  console.log(`selected ${value}`);
}

export default function App() {
  return (
    <div className="App" style={{ marginTop: "40px" }}>
      <Select
        defaultValue="lucy"
        style={{ width: 120 }}
        onChange={handleChange}
      >
        <Option value="jack">Jack</Option>
        <Option value="lucy">Lucy</Option>
        <Option value="disabled" disabled>
          Disabled
        </Option>
        <Option value="Yiminghe">yiminghe</Option>
      </Select>
    </div>
  );
}

My test

import "@testing-library/jest-dom/extend-expect";
import React from "react";
import { render, fireEvent, prettyDOM } from "@testing-library/react";
import App from "./App";

test("App Test", () => {
  const { queryAllByText, getByText, container } = render(<App />);

  expect(queryAllByText("Lucy").length).toBe(1);
  expect(queryAllByText("Jack").length).toBe(0);
  fireEvent.click(getByText("Lucy"));
  console.log(prettyDOM(container));
  // This line fails although I would expect the dropdown to be open and all the options visible
  expect(queryAllByText("Jack").length).toBe(1);
});

Here is a link to a codesandbox that reproduces the issue. (As mentioned, that code used to work in v3).

https://codesandbox.io/s/staging-shape-0xkrl?file=/src/App.test.js:0-494

Answer

After losing 2 days on this, here is the problem and solution:

Problem

In antd v3 it used to be possible to open a Select by doing selectHtmlElement.click(). You can test in the chrome dev tools console. In v4 this does not work.

This means that RTL which uses JSDOM under the hood will have the same behaviour. When you do fireEvent.click(selectElement); nothing happens !

Solution

This put me on the right track: https://github.com/ant-design/ant-design/issues/22074

The event you need to trigger is not a click() but a mouseDown() on the first child of the select.

const elt = getByTestId('your-select-test-id').firstElementChild;
fireEvent.mouseDown(elt); // THIS WILL OPEN THE SELECT !

Now at this point you probably want to select an option from the list but there is an animation going on so the following code (that used to work in v3) will also fail.

expect(getByText('Option from Select')).toBeVisible(); // FAILS !

You have 2 options, use toBeInTheDocument() or wait for the animation to be over by using waitFor(...)

Option 1: Faster but not totally accurate, I prefer to use this for simple use cases as it makes the tests faster and synchronous

expect(getByText('Option from Select')).toBeInTheDocument(); // WORKS !

Option 2: Slower as you need to wait for the animation to finish but more accurate for complex cases

await waitFor(() => expect(getByText('Option from Select')).toBeVisible()); // WORKS !
Categories
discuss

What is the “types first” Flow architecture?

A blog post by the Flow team describes a “re-architecture” of Flow called “types-first”. As far as I can tell, the only description is in this quote from the blog post:

“…it exploits full type annotations at file boundaries to perform better (more parallelizable and less redundant) separate compilation.”

Is there more detail about this anywhere? Specifically, I’m wondering what these full annotations are: what are the new restrictions on source code and declaration files?

For example, is this allowed?

import { func } from "./other-module";
export const myNumber = func(num1, num2);

It’s problematic in TypeScript, since the type of myNumber is impossible to resolve without knowing the type of func. Will the “types-first” re-architecture of Flow require users to write:

import { func } from "./other-module";
export const myNumber: number = func(num1, num2);

This is just one specific question I have. What I’m looking for is a little bit more information and a link to a document explaining all the known implications of the re-architecture.

Answer

It sounds really flashy and maybe it is under the hood. But in reality it’s quite simple. In your code snippet you’re absolutely correct, it pretty much means just that.

You must have an explicitly defined type before you export

Though not necessarily right before you export. The following works too.

const TestComponent = (): React.Node => {};

export default TestComponent;

It adds a little more overhead, but the benefits are:

  • improvements in performance because flow doesn’t need to scan all dependencies before it can give you soundness checks
  • More reliable code because flow runs within module boundaries so you don’t get flow errors that are caused by deeply nested dependencies.

They’ve also released a new blog post that goes into this further since types first have now been released officially. https://medium.com/flow-type/types-first-a-scalable-new-architecture-for-flow-3d8c7ba1d4eb

UPDATE The types-first architecture is now documented.

Categories
discuss

JavaScript declare a variable and use the comma operator in one statement?

it’s known that to declare multiple variables, one uses a format like:

let k = 0,
    j = 5 /*etc....*/

It’s also known that to execute multiple statements in one line (which is useful for arrow functions, making it not necessary to write the return keyword), the comma “,” operator is also used, like so:

let r = "hello there world, how are you?"
.split("")
.map(x => (x+=5000, x.split("").map(
  y => y+ + 8
).join("")))
.join("")

console.log(r)

not the most elegant example, but the point is you can execute multiple statements in one line, separated by a comma “,”, and the last value is returned.

So the question:

how do you combine both of these techniques? Meaning, how do we declare a variable in one line, and, one comma later, use that variable for something?

The following is not working:

let k = 0, console.log(k), k += 8

says

Uncaught SyntaxError: Unexpected token ‘.’

and without the console.log, it thinks I’m re-declaring k:

let k = 0, k += 8

gives

Uncaught SyntaxError: Identifier 'k' has already been declared

And putting the whole thing in parenthesis like so:

(let k = 0, k += 8);

gives

Uncaught SyntaxError: Unexpected identifier

referring to the keyword “let”. However, without that keyword, there is no problem:

(k = 0, k += 8);

except for the fact that k now becomes a global variable, which is not wanted.

Is there some kind of workaround here?

How can I use the comma operator together with a local variable declaration in JavaScript?

EDIT in response to VLAZ’s eval part of the answer, to pass parameters into eval, a custom function can be made:

function meval(mainStr, argList) {
    let ID = (
        Math.random().toString() + 
        performance.now().toString()
        
    ).split(".").join("").split("")
    .map(x => ("qwertyuio")[x])
    .join(""),
        varName = "$______"+ID+"_____$",
        str = `
        var ${varName} = {};
        (argList => {
            Object.entries(argList).forEach(x => {
                ${varName}[x[0]] = x[1];   
            })
             
        });
    `;
	let myEval = eval;
    
    
    
    
	return (() => {

		myEval(str)(argList)
		myEval(`
			${
				Object.keys(argList).map(x => 
					"let " + x + " = " + varName + "['" + x +"'];"
				).join("n")
			}
			${mainStr}
			delete window[${varName}];
		`)
		
	})()
}

meval(`
    var g = a.ko + " world!"
    
`, {
    a: {ko: "hi"}
})
console.log(g);

Answer

You cannot do that. The variable declaration syntax allows for a comma in order to declare multiple variables at once. Each variable can also be optionally initialised as part of the declaration, so the syntax is (more abstractly):

(var | let | const) variable1 [= value1], variable2 [= value2], variable3 [= value3], ..., variableN [= valueN]

However, that is NOT the comma operator. Same like how the comma in parseInt("42", 10) is also not the comma operator – it’s just the comma character that has a different meaning in a different context.

The real problem, however, is that the comma operator works with expressions, while the variable declaration is a statement.

Short explanation of the difference:

Expressions

Basically anything that produces a value: 2 + 2, fn(), a ? b : c, etc. It’s something that will be computed and produces something.

Expressions can be nested in many occasions: 2 + fn() or ( a ? ( 2 + 2 ) : ( fn() ) ) (each expression surrounded by brackets for clarity) for example. Even if an expression doesn’t produce a usable value that doesn’t change things – a function with no explicit return will produce undefined so 2 + noReturnFn() will produce gibberish but it’s still a valid expression syntax.

Note 1 of 2 (more in the next section): variable assignment is an expression, doing a = 1 will produce the value being assigned:

let foo;
console.log(foo = "bar")

Statements

These don’t produce a value. Not undefined just nothing. Examples include if(cond){}, return result, switch.

A statement is only valid standalone. You cannot nest them like if (return 7) as that’s not syntactically valid. You can further not use statements where an expression is expected – console.log(return 7) is equally invalid.

Just a note, an expression can be used as a statement. These are called expression statements:

console.log("the console.log call itself is an expression statement")

So, you can use an expression where a statement is valid but you cannot use a statement where an expression is valid.

Note 2 of 2: variable assignment is an expression, however variable declaration with assignment is not. It’s just part of the syntax for variable declaration statement. So, the two overlap but aren’t related, just how the comma operator and declaring multiple variables are similar (allow you to do multiple things) but not related.

console.log(let foo = "bar"); //invalid - statement instead of expression

Relation with the comma operator

Now we know that the difference and it should become easier to understand. The comma operator has a form of

exp1, exp2, exp3, ..., expN

and accepts expressions, not statements. It executes them one by one and returns the last value. Since statements don’t have a return value then they can never be valid in such context: (2 + 2, if(7) {}) is meaningless code from compiler/interpreter perspective as there cannot be anything returned here.

So, with this in mind we cannot really mix the variable declaration and comma operator. let a = 1, a += 1 doesn’t work because the comma is treated as variable declaration statement, and if we try to do ( ( let a = 1 ), ( a += 1 ) ) that’s still not valid, as the first part is still a statement, not an expression.

Possible workarounds

If you really need to produce a variable inside an expression context and avoid producing implicit globals, then there are few options available to you. Let’s use a function for illustration:

const fn = x => {
  let k = computeValueFrom(x);
  doSomething1(k);
  doSomething2(k);
  console.log(k);
  return k;
}

So, it’s a function that produces a value and uses it in few places. We’ll try to transform it into shorthand syntax.

IIFE

const fn = x => (k => (doSomething1(k), doSomething2(k), console.log(k), k))
                   (computeValueFrom(x));

fn(42);

Declare a new function inside your own that takes k as parameter and then immediately invoke that function with the value of computeValueFrom(x). If we separate the function from the invocation for clarity we get:

const extractedFunction = k => (
  doSomething1(k), 
  doSomething2(k), 
  console.log(k), 
  k
);

const fn = x => extractedFunction(computeValueFrom(x));

fn(42);

So, the function is taking k and using it in sequence few times with the comma operator. We just call the function and supply the value of k.

Cheat using parameters

const fn = (fn, k) => (
  k = computeValueFrom(x), 
  doSomething1(k), 
  doSomething2(k), 
  console.log(k), 
  k
);

fn(42);

Basically the same as before – we use the comma operator to execute several expressions. However, this time we don’t have an extra function, we just add an extra parameter to fn. Parameters are local variables, so they behave similar to let/var in terms of creating a local mutable binding. We then assign to that k identifier without affecting global scope. It’s the first of our expressions and then we continue with the rest.

Even if somebody calls fn(42, "foo") the second argument would be overwritten, so in effect it’s the same as if fn only took a single parameter.

Cheat using normal body of a function

const fn = x => { let k = computeValueFrom(x); doSomething1(k); doSomething2(k); console.log(k); return k; }

fn(42);

I lied. Or rather, I cheated. This is not in expression context, you have everything the same as before, but it’s just removing the newlines. It’s important to remember that you can do that and separate different statements with a semicolon. It’s still one line and it’s barely longer than before.

Function composition and functional programming

const log = x => {
  console.log(x);
  return x;
}

const fn = compose(computeValueFrom, doSomething1, doSomething2, log) 

fn(42);

This is a huge topic, so I’m barely going to scratch the surface here. I’m also vastly oversimplifying things only to introduce the concept.

So, what is functional programming (FP)?

It’s programming using functions as the basic building blocks. Yes, we do have functions already and we do use them to produce programs. However, non-FP programs essentially “glue” together effects using imperative constructs. So, you’d expect ifs, fors, and calling several functions/methods to produce an effect.

In the FP paradigm, you have functions that you orchestrate together using other functions. Very frequently, that’s because you’re interested in chains of operations over data.

itemsToBuy
  .filter(item => item.stockAmount !== 0)      // remove sold out
  .map(item => item.price * item.basketAmount) // get prices
  .map(price => price + 12.50)                 // add shipping tax
  .reduce((a, b) => a + b, 0)                  // get the total

Arrays support methods that come from the functional world, so this is a valid FP example.

What is functional composition

Now, let’s say you want to have reusable functions from the above and you extract these two:

const getPrice = item => item.price * item.basketAmount;
const addShippingTax = price => price + 12.50;

But you don’t really need to do two mapping operations. We could just re-write them into:

const getPriceWithShippingTax = item => (item.price * item.basketAmount) + 12.50;

but let’s try doing it without directly modifying the functions. We can just call them one after another and that would work:

const getPriceWithShippingTax = item => addShippingTax(getPrice(item));

We’ve reused the functions now. We’d call getPrice and the result is passed to addShippingTax. This works as long as the next function we call uses the input of the previous one. But it’s not really nice – if we want to call three functions f, g, and h together, we need x => h(g(f(x))).

Now finally here is where function composition comes in. There is order in calling these and we can generalise it.

const compose = (...functions) => input => functions.reduce(
    (acc, fn) => fn(acc),
    input
)

const f = x => x + 1;
const g = x => x * 2;
const h = x => x + 3;

//create a new function that calls f -> g -> h
const composed = compose(f, g, h);

const x = 42

console.log(composed(x));

//call f -> g -> h directly
console.log(h(g(f(x))));

And there you go, we’ve “glued” the functions together with another function. It is equivalent to doing:

const composed = x => {
  const temp1 = f(x);
  const temp2 = g(temp1);
  const temp3 = h(temp2);
  return temp3;
}

but supports any amount of functions and it doesn’t use temporary variables. So, we can generalise a lot of processes where we do effectively the same – pass some input from one function, take the output and feed it into the next function, then repeat.

Where did I cheat here

Hoo, boy, confession time:

  • As I said – functional composition works with functions that take the input of the previous one. So, in order to do what I had in the very beginning of the FP section, then doSomething1 and doSomething2 need to return the value they get. I’ve included that log to show what needs to happen – take a value, do something with it, return the value. I’m trying to just present the concept, so I went with the shortest code that did it to enough of a degree.
  • compose might be a misnomer. It varies but with a lot of implementations compose works backwards through the arguments. So, if you want to call f -> g -> h you’d actually do compose(h, g, f). There is rationale for that – the real version is h(g(f(x))) after all, so that’s what compose emulates. But it doesn’t read very well. The left-to-right composition I showed is usually named pipe (like in Ramda) or flow (like in Lodash). I thought it’d be better if compose was used for the functional composition headline but the way you read compose is counter-intuitive at first, so I went with the left-to-right version.
  • There is really, really a lot more to functional programming. There are constructs (similar to how arrays are FP constructs) that will allow you to start with some value and then call multiple functions with said value. But composition is simpler to start with.

The Forbidden Technique eval

Dun, dun, dunn!

const fn2 = x => (eval(`var k = ${computeValueFrom(x)}`), doSomething1(k), doSomething2(k), console.log(k), k)

fn(42);

So…I lied again. You might be thinking “geez, why would I use anybody this guy wrote hereme if it’s all lies”. If you are thinking that – good, keep thinking it. Do not use this because it’s super bad.

At any rate, I thought it’s worth mentioning before somebody else jumps in without properly explaining why it’s bad.

First of all, what is happening – using eval to dynamically create local binding. And then using said binding. This does not create a global variable:

const f = x => (eval(`var y =  ${x} + 1`), y);

console.log(f(42));         // 42
console.log(window.y);      // undefined
console.log("y" in window); // false
console.log(y);             // error

With that in mind, let’s see why this should be avoided.

Hey did you notice I used var, instead of let or const? That’s just the first of the gotchas you can get yourself into. The reason to use var is that eval always creates a new lexical environment when called using let or const. You can see the specs chapter 18.2.1.1 Runtime Semantics: PerformEval. Since let and const are only available within the enclosing lexical environment, then you can only access them inside eval and not outside.

eval("const a = 1; console.log('inside eval'); console.log('a:', a)");

console.log("outside eval");
console.log("a: ", a); //error

So, as a hack, you can only use var so that the declaration is available outside eval.

But that’s not all. You have to be very careful with what you pass into eval because you are producing code. I did cheat (…as always) by using a number. Numeric literals and numeric values are the same. But here is what happens if you don’t have a numeric:

const f = (x) => (eval("var a = " + x), a);

const number = f(42);
console.log(number, typeof number); //still a number

const numericString = f("42");
console.log(numericString, typeof numericString); //converted to number

const nonNumericString = f("abc"); //error
console.log(nonNumericString, typeof nonNumericString);

The problem is that the code produced for numericString is var a = 42; – that’s the value of the string. So, it gets converted. Then with nonNumericString you get error since it produces var a = abc and there is no abc variable.

Depending on the content of the string, you’d get all sorts of things – you might get the same value but converted to a number, you might get something different entirely or you might get a SyntaxError or ReferenceError.

If you want to preserve the string variable to still be a string, you need to produce a string literal:

const f = (x) => (eval(`var a = "${x}"`), a);

const numericString = f("42");
console.log(numericString, typeof numericString); //still a string

const nonNumericString = f("abc"); //no error
console.log(nonNumericString, typeof nonNumericString); //a string

const number = f(42);
console.log(number, typeof number); //converted to string

const undef = f(undefined);
console.log(undef, typeof undef); //converted to string

const nul = f(null);
console.log(nul, typeof nul); //converted to string

This works…but you lose the types you actually put in – var a = "null" is not the same as null.

It’s even worse if you get arrays and objects, as you have to serialise them in order to be able to pass them to eval. And JSON.stringify will not cut it, since it does not perfectly serialise objects – for example, it will remove (or change) undefined values, functions, and it flat out fails at preserving prototypes or circular structures.

Furthermore, eval code cannot be optimised by the compiler, so it will be drastically slower than simply creating a binding. If you are unsure that would be the case, then you probably haven’t clicked on the link to the spec. Do this now.

Back? OK did you notice how much stuff is involved when running eval? There are 29 steps per the spec and multiple of them reference other abstract operations. Yes, some are conditional and yes, the number of steps doesn’t necessarily mean it takes more time but it’s definitely going to do a lot more work than you need just to create a binding. Reminder, that cannot be optimised by the engine on the fly, so you it’s going to be slower than “real” (non-evaled) source code.

That’s before even mentioning security. If you ever had to do security analysis of your code you’d hate eval with passion. Yes, eval can be safe eval("2 + 2") will not produce any side effects or problems. The problem is that you have to be absolutely sure that you are feeding known good code to eval. So, what would be the analysis for eval("2 + " + x)? We cannot say until we trace back all possible paths for x to be set. Then trace back anything that is used to set x. Then trace back those, etc, until you find that the initial value is safe or not. If it comes from untrusted place then you have a problem.

Example: you just take part of the URL and put it in x. Say, you have a example.com?myParam=42 so you take the value of myParam from the query string. An attacker can trivially craft a query string that has myParam set to code that will steal the user’s credentials or proprietary information and send them over to himself. Thus, you need to ensure that you are filtering the value of myParam. But you also have to re-do the same analysis every so often – what if you’ve introduced a new thing where you now take the value for x from a cookie? Well, now that’s vulnerable.

Even if every possible value for x is safe, you cannot skip re-running the analysis. And you have to do this regularly then in the best case, just say “OK it’s fine”. However, you might need to also prove it. You might need a fill day just for x. If you’ve used eval another four times, there goes a full week.

So, just abide to the old adage “eval is evil”. Sure, it doesn’t have to be but it should be a last resort tool.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..