Coding: Fleeting Thoughts

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Yakk
Poster with most posts but no title.
Posts: 11105
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Sun Feb 10, 2019 4:08 pm UTC

Why would commits take 5 minutes?!
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

commodorejohn
Posts: 1157
Joined: Thu Dec 10, 2009 6:21 pm UTC
Location: Placerville, CA
Contact:

Re: Coding: Fleeting Thoughts

Postby commodorejohn » Sun Feb 10, 2019 4:26 pm UTC

Yakk wrote:Why would commits take 5 minutes?!

Obviously, because you're in a hurry and would rather they take five seconds. This is the way of things.
"'Legacy code' often differs from its suggested alternative by actually working and scaling."
- Bjarne Stroustrup
www.commodorejohn.com - in case you were wondering, which you probably weren't.

User avatar
Xenomortis
Not actually a special flower.
Posts: 1441
Joined: Thu Oct 11, 2012 8:47 am UTC

Re: Coding: Fleeting Thoughts

Postby Xenomortis » Sun Feb 10, 2019 6:58 pm UTC

I suspect something other than ~500 line text files are being committed...
Image

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Sun Feb 10, 2019 7:48 pm UTC

Yakk wrote:Why would commits take 5 minutes?!

Fine, it was closer to 3 minutes each. I thought it was a good idea to archive the xkcraftia backups in a git repository (since it's the default version control these days), thinking "oh, git can handle binary blobs well enough". Alas, it takes significantly longer to perform a commit than to copy the whole directory and the commit is significantly larger than storing a copy.
Note that these were commits for which nearly everything changed. (especially after the update to minecraft 1.13 in which every single piece of the world was repackaged)

Now borg was only twice as fast with committing a backup, but it did manage to de-duplicate a bunch of data so the end result is slightly smaller than separate backups.
Of course today's backup is be 'small' in both borg and git because less than a tenth of the files have changed, but now I've got borg set up so screw (g)it.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11105
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: Coding: Fleeting Thoughts

Postby Yakk » Mon Feb 11, 2019 9:13 pm UTC

"oh, git can handle binary blobs well enough"


Hahahahahahahahahaahahahahahahahaha

ahum.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Mon Feb 25, 2019 5:12 pm UTC

Code: Select all

...
kmlReq.addEventListener('load', () => {
   const routes = toGeoJSON.kml(kmlReq.responseXML)
   const features = routes.features.map(({'geometry': g, 'properties': { 'name': n='' }}) => ({'name': n, 'geom': g})) //flatten the structure a bunch
   const [points,paths] = features.partition(({'geom': {'type': t}}) => t == 'Point') //Array.prototype.partition should be included in ES2020
...


ECMAScript is starting to look like a proper language what with arrow functions, destructuring, imports and template literals. Now all it needs is a super-strict mode (no side-effects allowed), a good type system and a lazy runtime. :mrgreen:

Xanthir, since you're the standards guy around here, should I use quotes around object keys? Should I use on<x> rather than addEventListener for all eventing? Should I use semicolons to end statements?

User avatar
Xanthir
My HERO!!!
Posts: 5377
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Mon Feb 25, 2019 7:28 pm UTC

Flumble wrote:
Xanthir, since you're the standards guy around here, should I use quotes around object keys?

No, it's just a few unnecessary characters. Unless you're writing JSON, in which case it's required.

Should I use on<x> rather than addEventListener for all eventing?

Feel free to for small examples, but since only one source can use the onFoo attribute at a time, using aEL is always the more reliable method. We've been looking for a while at finally adding a .on() API that makes slightly better choices for events anyway.

Should I use semicolons to end statements?

Yes. No-semicolon people are the devil.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Soupspoon
You have done something you shouldn't. Or are about to.
Posts: 3954
Joined: Thu Jan 28, 2016 7:00 pm UTC
Location: 53-1

Re: Coding: Fleeting Thoughts

Postby Soupspoon » Mon Feb 25, 2019 8:46 pm UTC

I agree;

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Tue Feb 26, 2019 12:00 am UTC

Tanks for the answers. :)
Xanthir wrote:Yes. No-semicolon people are the devil.

In my defence, most of the stuff I write unambiguously continues a statement at the end of a line (with a binop or opening brackets) or ends a statement on the next line (with a keyword).


Unrelated thought: I've recently looked into the Assignment Problem and "implemented" (copy+paste another implementation and change the syntax to match the target language) the hungarian method in a new language, because it promised to be O(n^3) and was easy enough to move (and vaguely understand) the code.
But the assignment problem can be expressed in a linear program (link because I keep forgetting the specifics) and linear programs can be solved in O(n^2.5) these days. So I wonder if I should just use a general solver in the future.
Will a solution always have 1s and 0s for all worker-job pairings? (assuming I throw in some variation in the weights so you don't end up with e.g. two workers with exactly the same weights so putting 0.3 and 0.7 worker on a job is a valid solution)

Tub
Posts: 430
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Tue Feb 26, 2019 1:01 pm UTC

Flumble wrote:

Code: Select all

...
kmlReq.addEventListener('load', () => {
   const routes = toGeoJSON.kml(kmlReq.responseXML)
   const features = routes.features.map(({'geometry': g, 'properties': { 'name': n='' }}) => ({'name': n, 'geom': g})) //flatten the structure a bunch
   const [points,paths] = features.partition(({'geom': {'type': t}}) => t == 'Point') //Array.prototype.partition should be included in ES2020
...

Using an arrow function means that you can't use 'this' to refer to kmlReq in the callback. Refering to kmlReq is going to lead to fun things if you ever decide to load multiple shapefiles and refactor that thing into a loop, or you're re-using kmlReq for a second request further down the function.

Flumble wrote:Xanthir, since you're the standards guy around here, should I use quotes around object keys?

Are you using or planning on using the closure compiler? If you are, then quotes have a special meaning: unquoted property names may be minified, quoted property names may not.

(The ability to mangle property names puts the closure compiler way ahead of any other minifier I know, but the hassle of distinguishing between minifiable and non-minifiable property names is often more work than it's worth.)

Otherwise, I usually omit the quotes because it's less typing and it looks better with my current syntax highlighting when they're not string-coloured. :roll:

Flumble wrote:Should I use semicolons to end statements?

To elaborate on Xanthirs answer, automatic semicolon insertion is the devil. Unfortunately, placing semicolons doesn't help against its evils, nor can it be disabled.

It bears repeating that one of the following pieces of code is different than the others. If you can't spot which and why, then you need to install a linter and start placing semicolons today.

Code: Select all

return {
  a: 42
}

Code: Select all

return
{ a: 42 }

Code: Select all

return { a:
42 }


Flumble wrote:[..]hungarian method in a new language, because it promised to be O(n^3)
[..]
[..]linear programs can be solved in O(n^2.5) these days.

Aside from the issue that (binary) integer programming has different complexities than linear programming: tell me, what does the n refer to in both of these formulas?

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Tue Feb 26, 2019 2:50 pm UTC

Tub wrote:Using an arrow function means that you can't use 'this' to refer to kmlReq in the callback. Refering to kmlReq is going to lead to fun things if you ever decide to load multiple shapefiles and refactor that thing into a loop, or you're re-using kmlReq for a second request further down the function.

Of course if I'd refactor it to a loop it would look like

Code: Select all

for (const addr of addresses) {
   const req = new XMLHttpRequest()
   req.addEventListener('load', () => somethingWith(req))
   ...
}

There's no funny business with all the reqs being one and the same reference despite being block-scoped. At least there wasn't with for (const v of [1,2,3]) {const w = v; setTimeout(()=>console.log(w), 50*v)}.

Tub wrote:Otherwise, I usually omit the quotes because it's less typing and it looks better with my current syntax highlighting when they're not string-coloured. :roll:

My highlighter (Atom) is behaving really weird (an identifier is in order of precedence: green in a const declaration or if it's a single capital, yellow if it's a CSS prop or HTML attr name and has a dot on the left side, orange if it has an opening paren, purple if it has a dot on either side, or grey), so only quotes make them stand out. But the thing about possibly minifying sounds like a good enough reason not to do it. It's not like it makes a difference for the parser or makes it more/less valid JSON anyway.

Re: ASI
Spoiler:

Code: Select all

return ; //<- inserted here
{ a: 42 } ; //<-and here

Yeah I came across that too when advocating my non-use of semicolons. Opening-bracket-on-the-same-line styles save the day once more. :lol:


Tub wrote:
Flumble wrote:[..]hungarian method in a new language, because it promised to be O(n^3)
[..]
[..]linear programs can be solved in O(n^2.5) these days.

[..]tell me, what does the n refer to in both of these formulas?

Hmm, for the hungarian method n≈max(workers,jobs) ⇒ O(n^3) and an LP encoding is n≈workers*jobs ⇒ O(n^5). Why do you ask? :roll:
(does binary optimization have a better algorithm than real-valued optimization?)

User avatar
Xanthir
My HERO!!!
Posts: 5377
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Tue Feb 26, 2019 3:03 pm UTC

Tub wrote:
Using an arrow function means that you can't use 'this' to refer to kmlReq in the callback.


...huh. I never knew that aEL passed the object you registered the event on via 'this'. Interesting.

Refering to kmlReq is going to lead to fun things if you ever decide to load multiple shapefiles and refactor that thing into a loop


Specifically, Tubs is referring to the following common problem:

Code: Select all

for(var i = 0; i < 5; i++) {
  setTimeout(()=>alert(i), 50);
}


Immediately after running, you'll get five alerts, all of which say "5". This is because all the functions grabbed the *same* variable binding to i, which was mutated in place by the loop, so at the end i is set to 5 and they all see that.

The solution to this used to be annoying, but luckily it's pretty trivial these days. If what you're looping over is iterable, you can just use a for-of loop and it works automatically:

Code: Select all

for(var el of list) {
  setTimeout(()=>alert(el.name), 50);
}


Alternately you can just introduce another, block-scoped variable (using the "let" or "const" keywords instead of "var") inside the loop and have the functions use that instead:

Code: Select all

for(var i = 0; i < 5; i++) {
  const j = i;
  setTimeout(()=>alert(j), 50);
}


Both of these work because you get a brand new binding of the variable on each iteration, so each function is seeing totally separate variables.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Tue Feb 26, 2019 3:35 pm UTC

Xanthir wrote:Alternately you can just introduce another, block-scoped variable (using the "let" or "const" keywords instead of "var") inside the loop and have the functions use that instead:

You don't even need to introduce an alias; just stop using var (which binds the variable to the whole function scope so it exists after your loop is done) altogether:

Code: Select all

for(let i = 0; i < 5; i++) {
  setTimeout(()=>alert(i), 50);
}


[edit]Well, it still makes no sense that the i in the arrow gets/is a different binding for each iteration as pointed out below. But hey, it automagically works the way you want it to.
Last edited by Flumble on Thu Feb 28, 2019 4:23 pm UTC, edited 2 times in total.

User avatar
Xanthir
My HERO!!!
Posts: 5377
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Tue Feb 26, 2019 5:43 pm UTC

Ah! I didn't realize that plain-for would establish the correct binding scopes for block-scoped variables! That's exciting!
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

Tub
Posts: 430
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Tue Feb 26, 2019 10:50 pm UTC

Flumble wrote:

Code: Select all

return ; //<- inserted here
{ a: 42 } ; //<-and here

Yeah I came across that too when advocating my non-use of semicolons. Opening-bracket-on-the-same-line styles save the day once more. :lol:

Interesting that you got it wrong, then. Hint: that's not an object literal there. I predict you're going to learn about one more arcane JavaScript feature today :lol:

Another valid answer to the your question of quoting property names is that you should always quote them to turn this silent unexpected behaviour into a syntax error.

Flumble wrote:(does binary optimization have a better algorithm than real-valued optimization?)

The fundamental theorem of linear programming only holds for continuous variables. As soon as you go discrete, bad things happen to your complexity.

Xanthir wrote:you can just use a for-of loop and it works automatically:

Code: Select all

for(var el of list) {
  setTimeout(()=>alert(el.name), 50);
}

I tested that, it will also output the last element repeatedly. Further research says that let and const and their block level scopes do all the magic; for-of does nothing relevant.

(I'm glad we talked about this; yesterday I totally would have gotten some of these wrong!)

User avatar
Xanthir
My HERO!!!
Posts: 5377
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Wed Feb 27, 2019 1:03 am UTC

...dangit, I definitely *meant* to type "let" in that example, too.

Yeah, "var" is the thing that breaks stuff. But *also*, it's not just the let/const keyword doing the work; it's important that the for-of loop is specified to create a particular (non-obvious, non-trivial) set of binding scopes that causes it to work correctly. I wasn't aware that plain-for would do the same scope stuff.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

User avatar
phlip
Restorer of Worlds
Posts: 7565
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Feb 27, 2019 1:20 am UTC

Flumble wrote:
You don't even need to introduce an alias; just stop using var (which binds the variable to the whole function scope so it exists after your loop is done) altogether:

Code: Select all

for(let i = 0; i < 5; i++) {
  setTimeout(()=>alert(i), 50);
}

... there must be some deep magic going on there to let you use "i++" in the loop statement and yet have the "i"s in separate loop iterations be different variables for the closures...

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

User avatar
Xanthir
My HERO!!!
Posts: 5377
Joined: Tue Feb 20, 2007 12:49 am UTC
Location: The Googleplex
Contact:

Re: Coding: Fleeting Thoughts

Postby Xanthir » Wed Feb 27, 2019 1:49 am UTC

Aha, indeed: https://noraesae.net/2017/09/14/lexical ... -for-loop/

It examines what bindings are formed by the initializer, then generates a succession of nested binding scopes establishes new variables of the same name, initialized with the value of the previous binding scope's version of the variable at the end of the loop! *Then* it executes the incrementor on the newly created inner scope variable.
(defun fibs (n &optional (a 1) (b 1)) (take n (unfold '+ a b)))

Tub
Posts: 430
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Wed Feb 27, 2019 10:44 am UTC

So the tl;dr is that let/const are not just scoping restrictions, but the runtime will actually create a new variable each time program flow encounters a let/const declaration for capturing purposes. Hence, implementing let/const requires more than resolving naming conflicts, enforcing temporal dead zones and preventing const assignments. It's impossible to emulate let/const using var with a simple compiler pass, and babel'ing some of todays examples exhibits interesting workarounds.

'for' loops have additional logic such that any variable declared in the initialization will also be considered a new variable each loop. Thinking about it, they have to be, if you want something like

Code: Select all

for (const i of [1,2,3])

to work.

None of this will prevent you from modifying the variable after capturing. This one still prints a bunch of nulls:

Code: Select all

for (let i of [1,2,3]) {
    setTimeout(()=>console.log(i), 100);
    i = null;
}


It's unfortunate that the MDN article on let mentions nothing of this.

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Wed Feb 27, 2019 12:49 pm UTC

Tub wrote:Hint: that's not an object literal there.

whyyyyyy.jpg
whyyyyyy.jpg (29.16 KiB) Viewed 1061 times

It kind of makes sense that javascript would prefer parsing it as a block rather than an expression statement. But labels must not exist outside of assembler languages.

But wait! There's more:

Code: Select all

()=>{
   return
   {a: 42, u: 1337} // Syntax error at the second colon
}

Shouldn't an object literal be a valid expression statement? Why isn't the parser retrying it as an expression? :?


phlip wrote:... there must be some deep magic going on there to let you use "i++" in the loop statement and yet have the "i"s in separate loop iterations be different variables for the closures...

I think the javascript gods smiled, since it does work exactly the way you want it to. :mrgreen:

User avatar
phlip
Restorer of Worlds
Posts: 7565
Joined: Sat Sep 23, 2006 3:56 am UTC
Location: Australia
Contact:

Re: Coding: Fleeting Thoughts

Postby phlip » Wed Feb 27, 2019 1:17 pm UTC

Flumble wrote:
Shouldn't an object literal be a valid expression statement? Why isn't the parser retrying it as an expression? :?

I dunno, I prefer the simplicity of "when we see an open brace, if we're expecting a statement, it's a block, if we're expecting an expression, it's an object"... sure, it's still not as clear as if we weren't overloading the characters in the first place, but at least it's simple and consistent.

Anyway, you can always force the issue by wrapping it parens:

Code: Select all

return
({a: 5}) // is parsed as an object literal
// (still isn't actually returned, though)

Spoiler:
(btw if you've ever seen that "wat" presentation... y'know, the one with:

Code: Select all

>>> [] + []

>>> [] + {}
[object Object]
>>> {} + []
0
>>> {} + {}
NaN
then this whole thing is, like, a third of the answer to what's going on there...)

Code: Select all

enum ಠ_ಠ {°□°╰=1, °Д°╰, ಠ益ಠ╰};
void ┻━┻︵​╰(ಠ_ಠ ⚠) {exit((int)⚠);}
[he/him/his]

DavidSh
Posts: 182
Joined: Thu Feb 25, 2016 6:09 pm UTC

Re: Coding: Fleeting Thoughts

Postby DavidSh » Wed Feb 27, 2019 3:17 pm UTC

Flumble wrote:Unrelated thought: I've recently looked into the Assignment Problem and "implemented" (copy+paste another implementation and change the syntax to match the target language) the hungarian method in a new language, because it promised to be O(n^3) and was easy enough to move (and vaguely understand) the code.
But the assignment problem can be expressed in a linear program (link because I keep forgetting the specifics) and linear programs can be solved in O(n^2.5) these days. So I wonder if I should just use a general solver in the future.
Will a solution always have 1s and 0s for all worker-job pairings? (assuming I throw in some variation in the weights so you don't end up with e.g. two workers with exactly the same weights so putting 0.3 and 0.7 worker on a job is a valid solution)


The assignment problem, formulated as a linear program in the natural way, is a member of the class for which, barring ties, optimal solutions to the linear program have all integer values. Basically, all relevant submatrices of the constraint matrix have determinants in {0, +1, -1}.

User avatar
Flumble
Yes Man
Posts: 2159
Joined: Sun Aug 05, 2012 9:35 pm UTC

Re: Coding: Fleeting Thoughts

Postby Flumble » Wed Mar 06, 2019 10:41 pm UTC

I have a web page with a bunch of iframes in them (because I think that's the best way to show multiple pages side by side) all on the same domain, but I want to go back and forth in history in each frame independently. Unfortunately all frames push history to a global stack, so window.history.back() goes back in whichever frame last opened a page regardless of which frame made the function call.

Assuming there is a workaround, what's the least hacky way to accomplish it? (StackOverflow is a mess on this subject)

Tub
Posts: 430
Joined: Wed Jul 27, 2011 3:13 pm UTC

Re: Coding: Fleeting Thoughts

Postby Tub » Thu Mar 07, 2019 3:41 am UTC

frames are just windows. Isn't there something like myIframe.contentWindow.history.back() ?


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 14 guests