<ljharb>
ec^: it's a bit vague. seems like A should be split up into multiple tasks but i don't know what it's doing
<ec^>
It's no particular task. It's a possible interaction that breaks my concurrency system, and I'm trying v. hard to have an unbreakable concurrency system. :P
<ljharb>
hm, ok
<ljharb>
so can't A just wait for y to be unlocked?
<ljharb>
or will B's action on y potentially screw with it
<ec^>
no, B is waiting on x after having taken y.
<ec^>
so B will never free x, because A already has y.
<ljharb>
ahh right, ok
<ec^>
tentative thoughts:
<ljharb>
i think that B can't take y until it can also take x.
<ec^>
ugh no that doesn't help
<ec^>
like, this feels unresolvable
<ljharb>
in other words, to lock anything, it must be able to grab everything.
<ec^>
yeah.
<ljharb>
so B shouldn't lock y until A has released x (and nothing else has locked x or y)
<ec^>
it might just require an unlock. but UGH
<ec^>
yeah like I said above, this is basically *architecting* a problem that atomic-multilock doesn't solve
<ljharb>
when you say "atomic multilock" you mean B locking y without locking x?
<ec^>
so I should have also specified that B, too, needs to preform actions on the first one it takes, before it can determine what the second it should take is
<ljharb>
ok so i think that's the antipattern
<ec^>
no, I mean B being able to just say `lock(x, y)` solves it in my original query
<ljharb>
i think that each task needs to be able to declare up front which things it might *ever* need to lock
<ljharb>
and, it can't lock anything until it can lock all of them
<ec^>
yeah had a similar thought a moment ago
<ec^>
and obv. this breaks that because the second thing is non-deterministic
<ljharb>
and non-determinism is also something that should be avoided :-)
<ljharb>
rofl just thought of that. how come nobody's ever done that to me before
<ec^>
now it's a race condition.
<ec^>
ljharb: ...
<ec^>
oh my,
<ec^>
lol.
<ljharb>
lol sorry, paying attention
<purr>
lol
<ec^>
no.
<ec^>
bad.
<ec^>
-trout @ ljharb
<ec^>
-find fish
<purr>
ec^: Found: gqbe and gqbe'smemory
<ec^>
-gqbe @ ljharb
<purr>
ljharb: has no memory. basically a fish with tits.
<ec^>
I,
<ec^>
I,
<ec^>
what
<gq>
a;oisdyf;aosidyf;aoisdyf;oaisydf
<gq>
AHAHAHAHA
<ec^>
what.
<gq>
fucking
<gq>
jesus
<gq>
christ
<gq>
i'm drunk and i forgot about that
<ljharb>
ok so. A needs a read-lock on X, so it can look up y - right, understood
<ec^>
hm
<ec^>
so no that's fine
<ec^>
because read-locks can be mutual
<ec^>
hm
<ljharb>
ec^: but then once it's found y, it should release x, and then wait for y - ie, dispatch to a new task
<gq>
-gqbe
<purr>
gq: has no memory. basically a fish with tits.
<gq>
-gqbe'smemory
<purr>
gq: none. none at all. they're like a fish with tits.
<ec^>
so like the only problematic situation is where something *needs write-lock* (i.e. *exclusive* lock, not inclusive lock) to determine a second lock-target
<ljharb>
ec^: meaning a given task must only have one locking stage, at the beginning, and one unlocking stage, at the end
<gq>
they're even phrased differently what the hell
<ec^>
that seems like, *insanely* obscure, and I think I'm fine with ignoring that.
<ec^>
-factoid gqbe
<purr>
ec^: Popularity: 2, last changed by: remy, 1kſ 223ſ 196mſ ago
<ec^>
-factoid gqbe'smemory
<purr>
ec^: Popularity: 1, last changed by: gqbe, 1kſ 222ſ 175mſ ago
<ec^>
who the fuck is remy
<ec^>
and they were changed within a few minutes of one another
<ec^>
super-strange
<ec^>
ljharb: see, *I* agree with that; and my language is going to enforce that
<gq>
that was another of my nicks
<gq>
i had like 5
<ec^>
(in fact, my language actually doesn't allow explicit locking or unlocking: you have to do things as *methods*, and they operate over a set of information that is locked by dint of how it's declared)
<gq>
all i remember is that was the morning i was super manic (well one of the mornings)
<ljharb>
ok
<ec^>
but in terms of Paws itself, the VM / core design, I can't reasonably restrict that
<gq>
and somebody in here asked if i was on crack
<ec^>
there's no such thing as a procedure or anything else with an explicit start/end, so there's really no way to restrict that even if I wanted to
<gq>
anyway you're getting shit done so
* gq
shutting up
<ec^>
those are all higher-level concepts implemented at a higher level than the one I'm discussing
<ljharb>
ec^: wait, why can't you
<ljharb>
ok what are the concepts of your system's level then
<ec^>
Paws is a vm where you climb a graph of opaque data-nodes, manipulating the *relationships* between them, and expressing locking/unlocking on them.
<ec^>
Thats, like, literally it.
<ec^>
everything else is farmed out to a lower-yet level (atomic operations on that opaque data, preformed by the underlying implementation), or a higher level (abstractions constructed of *multiple* operations on underlying-data, or constructed operations on the interrelatory metadata we're speaking of here)
<ljharb>
ok right so
<ljharb>
each node has locking/unlocking
<ec^>
a little more than that, because locking can also cascade through the graph, but, besides the point
<ljharb>
i'm saying that you can hardcode into the system that locking happens first, then the task runs, then the unlocking happens. right?
<ec^>
See, this isn't a synchronous system: there's no explicit ‘after’ an operation happens. (There's also no wholesale ‘operation’, but that's a nitpick)
<ec^>
or to re-phrase that, the ‘after’ may never come. Somebody else may be doing your unlocking for you, at a different location in the code.
* ec^
backs up
<ec^>
yeah, convinced my earlier concern is a non-starter *anyway*.
<ljharb>
hm
<ec^>
You'd have to, basically, *need to write something* to determine a later thing to lock
<ec^>
that's almost by-definition impossible, no?
<krainboltgreene>
Bewp.
<ec^>
krainboltgreene: 'allo!
<krainboltgreene>
ec^: For future reference, I basically 90% do Ruby and Node HTTP HATEOAS API development.
<ec^>
HATEOAS?
<ec^>
krainboltgreene: what do you find *interesting*, not what do you do at your job
<krainboltgreene>
That's what I find interesting D:
<purr>
ec^: Found: funstuff, green, troll, ##c, and object-oriented
<ec^>
-##c @ katymoe
<purr>
katymoe: < prophile> that's because ##C is so full of trolls you could give it a dusting of snow and call it norway
<ec^>
Hrorek: sorry, I was asleep.
<ec^>
Hrorek: being sick is leading to me sleeping, like, 11 hours a day. That's making it hard to reliably hook up with you, with our 11.5-hour-rotated sleep schedules.
<ec^>
krainboltgreene: I mean, the accepted answer is terrible. (Don't answer unless you know, geeze?)
<ec^>
but otherwise I'm not seeing it?
<ec^>
rvm lol
<purr>
lol
<krainboltgreene>
Well, for one OSX comes with Rubygems already (Ruby 2.0.0)
<krainboltgreene>
And the answer talks about creating...a partition?
<krainboltgreene>
It's just rather weird.
<katymoe>
ec^: lol
* katymoe
joins ##C
<krainboltgreene>
#haskell is another one.
<krainboltgreene>
Full of people looking to be better computers than humans.
<ec^>
goddamnit irccloud, I will never understand you
<katymoe>
General Functional Programming?
<ec^>
lol as in FP-cast-as-a-solution-to-everyday-programming-problems,
<purr>
lol
<Hrorekr>
ec^, gonna spend this night learning
<ec^>
or rather, exclusively / hostile-ly functional *languages* cast as general programming languages.
<ec^>
Hrorekr: ah, you're staying up? cool! let me know if you dive into my links on continuations, and want to talk about them more.
<ec^>
or if you want to move on from there into more Paws-y stuff.
<Hrorekr>
ec^, more paws-y stuff
<ec^>
hahah okay. I'll drag myself away in a few minutes and go sit down to work with you. (=
<ec^>
krainboltgreene: ugh I miss being in love with schemes
<krainboltgreene>
You check out guile?
<ec^>
I have an allergic aversion to anything labeled ‘GNU.’
<ec^>
those guys scare me.
<ec^>
-feet
<purr>
ec^: <+micahjohnston> rms is a retard who eats his feet and never makes anything
<ec^>
-learn feet =~ s/retard/<snip>/
<purr>
ec^: Changed `feet` to: <+micahjohnston> rms is a <snip> who eats his feet and never makes anything
VanguardVivian has quit [Ping timeout: 255 seconds]
<ec^>
Hrorekr: 'allo!
<Hrorekr>
ec^, hi
VanguardVivian has joined #elliottcable
<ec^>
VanguardVivian: oh hi
<ec^>
VanguardVivian: thought: your CS educational career might be much more fruitful if you hang out in here regularly. ;)
<Hrorekr>
ec^, who is VanguardVivian ?
<ec^>
Hrorekr: friend of mine. Starting school for CS.
<ec^>
Hrorekr: @VanguardVivia.
<ec^>
er,
<ec^>
@VanguardVivian.
<ec^>
VanguardVivian: if the things you see people talking about in here excite you, you'll get introduced to much more exciting and engaging shit than your university will expose you to;
<ec^>
but correspondingly, if you're constantly bored or lost by the things floating past in here, it might not be the career for you. ¯\_(ツ)_/¯
<Hrorekr>
I started college a few months ago too
<VanguardVivian>
Good points, ec
<ec^>
Hrorekr, VanguardVivian
<ec^>
VanguardVivian, Hrorekr
* ec^
bows back
<Hrorekr>
how old are you VanguardVivian
<ec^>
omg brr is in here, glowcoil
<ec^>
brr: hi!
gq has joined #elliottcable
<ec^>
Hrorekr: so, we covered continuations.
<ec^>
Hrorekr: I know I mentioned some Paws stuff, but I'm just going to start over from what I know you had a firm basis in.
<Hrorekr>
ok
<ec^>
So, in a traditional language with continuations, they're a type expressing a partially-completed function.
<ec^>
(Let me know if anything *isn't* ringing any bells. Don't want to lose you.)
<Hrorekr>
ec^, in paws can you do infinite recursion because there isn't any stack to blow?
<ec^>
yes! absolutely!
<ec^>
:D
<Hrorekr>
nice
<ec^>
It's not even really ... recursion, anymore, at Paws' level. but we'll come back to that later.
<ec^>
and there are *infinitely* cooler patterns than recursion that CPS enables (but again: coming back later)
<ec^>
in Paws, we extend continuations to also cover *un-started* procedure: this obviates the need for a ‘procedure’ type at all; when you invoke a procedure, you're actually just invoking a continuation *that doesn't have any context yet*.
<ec^>
so if you remember |this| syntax from last night,
<ec^>
in addition to {{ continuations that look |like| this }} and {{ ones |that| look like this }},
<ec^>
you can have {{|| ones that look like this }}, so to speak.
<Hrorekr>
uhm, I don't remember it from last time
* ec^
nods
<ec^>
okay. I'll back up a tad.
<ec^>
the example JavaScript function we used looked like this:
<ec^>
so yesterday, we had this JavaScript example:
<ec^>
`function square(n) { result = mult(n, n); console.log(result) }`
<ec^>
now, if we “advance” the evaluation of that chunk of code by one step, the very first thing that happens is that `mult()` gets invoked.
<ec^>
so let's imagine that's happened. If we had a continuation for the *current state* of that function, at that point, it would look like this:
<ec^>
{{ result = |mult(n, n)|; console.log(result) }}
<ec^>
where the ||'s indicate the last AST node evaluated, or more particularly, *“where the value goes” when something resumes it with a value.
<ec^>
(we have ‘a continuation’, and |this| is ‘where it continues from’)
<ec^>
are we back on the same page? (=
<Hrorekr>
uhm, I don't understand
* ec^
nods
<ec^>
Hrorekr: Did you re-read out conversation from last night, already?
<Hrorekr>
wait
<Hrorekr>
I get it now
<ec^>
yes?
<ec^>
Hrorekr: What is a continuation, in your own words. GO!
<Hrorekr>
|this| is what that will get the value passed to it
<Hrorekr>
uh, it is like giving a function something that was processed before by another function
<Hrorekr>
right?
<ec^>
hm. Re-phrase, I didn't grok that.
<Hrorekr>
uhm
<ec^>
‘processed before?’
<Hrorekr>
you keep passing data around, processing it bit by bit
<Hrorekr>
that?
<ec^>
That's actually insightful. Yes, that is correct!
<ec^>
So, we talked a bit about this last night, but since you got a little lost, I want to re-cover it to make sure we're on the same page.
<ec^>
*Continuations* exist in many languages, as a construct. *Continuation-passing style*, or CPS, though, while being famous, is a little rarer.
<ec^>
The first exist, for instance, in lisps; where you can explicitly create a continuation with the `call/cc` mechanism
<ec^>
(which stands for “call-with-current-continuation”)
<ec^>
note the word *current*: In this case, creating a continuation is *explicit*, on the part of the function being paused.
<Hrorekr>
call/cc is something like ES6 or python generators?
<ec^>
I've heard so, but I've actually never used generators.
<ec^>
But yes, that's a comparison I've heard before, so I suspect you're on the right track.
<ec^>
Of note: generators are usually compared to *coroutines*, not specifically continuations ... but ‘coroutines’ and ‘continuations’ are very similar concepts in lots of ways. I'll come back and tell you about those in a bit, if you'd like. (=
<Hrorekr>
sure
<ec^>
so, for instance, although lisp's syntax is very, very different; you might do something like this, in JS-syntax:
<ec^>
WAIT
<ec^>
PAUSE
<ec^>
LOL'ING
<purr>
LOL
<ec^>
me: “was going to say, I'm on a teaching-Akshat-programming-things binge; and I could extend that to you if you like.”
<ec^>
... anyway. still laughing out loud. okay. so. uh.
<Hrorekr>
the irony
<ec^>
imaginary JavaScript example of Scheme's call-with-current-continuation feature:
<ec^>
function mult(a, b, $return) { $return(a, b) }
<ec^>
function square(n) {
<ec^>
result = call_with_current_continuation(mult, n, n)
<ec^>
console.log(result)
<ec^>
}
<ec^>
fack
<ec^>
same typo as last night
<ec^>
IGNORE THAT
<ec^>
function mult(a, b, $return) { result = a * b; $return(result) }
<ec^>
function square(n) {
<ec^>
console.log(result)
<ec^>
}
<ec^>
result = call_with_current_continuation(mult, n, n)
<ec^>
there we go.
<ec^>
so, call/cc-type constructs take a function or other ‘invokable’¹, and, well, invoke it, just like a normal function call …
<ec^>
but in the process, they freeze the current stack state *of the caller* (the one inside which you typed call/cc), drop that stack, and then pass that packaged-up stack-state as the first argument.
<Hrorekr>
What's the advantage of this?
<ec^>
(1. of note, ‘invokable’ includes *other continuations*. This is really important, although possibly non-obvious. This means you can exchange information back-and-forth between two functions by passing continuations back and forth between them.)
* ec^
grins
<Hrorekr>
takes up less memory and lesser calls to the stack?
<ec^>
ahhah that's very much a side-effect.
<ec^>
Hrorekr: quick question
<ec^>
actually a couple
<ec^>
to get meta for a second
<ec^>
Okay. So, most people, when teaching, use long-form code examples. I *hate* that, personally, but I seem to be the outlier. I don't like trying to trawl through twenty lines of ugly syntax, when five English-prose sentences would suffice to convey the topic.
<ec^>
That said, I'm pretty sure I'm unusual. So, would you prefer a code-example, or for me to write it all out?(I ask, because I know my long-form prose answers can get bogged-down and confusing sometimes. It's a personality flaw. :P )
<Hrorekr>
write it all out
<Hrorekr>
I will ask for code when I need it
<ec^>
Second: I touched on this last night, but avoided asking directly; but I know you mentioned this *before* when talking about how un-effective your teachers were at Uni, for you ...,
<ec^>
but do you prefer being *led*, or *followed*? That is, would you prefer I talk, or would you prefer I present you problems so you have to figure it out for yourself?
<Hrorekr>
both approaches are okay
<ec^>
Being made to figure it out for yourself can be very frustrating, and a lot slower; but will lead to a better retention of the topic in the long-run.
* ec^
nods
<ec^>
kk!
<ec^>
So, continuations have lots of interesting computer-science *theory* consequences, especially in regards to compiler optimization tactics;
<ec^>
but that's far from the purpose of their existence. (Hell, in most of the languages that *implement* continuations, ‘stack depth’ isn't really a concern: tail-call optimization, or being inherently stackless already, or ...)
<ec^>
They're interesting for their *expressivity* characteristics, not their performance ones. That is, they allow the programmer, their user, to express entirely new forms of control-flow that you cannot express with traditional stack-based function-dispatch and control-flow-branching.
<ec^>
(Hell, it turns out you can implement almost any other control-flow mechanism *using only continuations*: continuations can be used at the user-level, by the programmer, to imitate if/then/else; looping and iteration; even more complex things like exception-throwing and coroutines.)
<ec^>
(I'll touch on that more later. But I promise you, it's insanely cool. =)
<ec^>
but at their most basic, the thing they can do that you cannot do with functions, is the very example we're playing with right now.
<ec^>
Let's go backwards. here's the using-continuations example:
<ec^>
function B($return, arg) { it = complex_operation(arg); $return(it) }
<ec^>
function A(n) {
<ec^>
it = call_with_current_continuation(B, "Akshat")
<ec^>
print(it)
<ec^>
}
<ec^>
I re-named some variables, but it's the same basic flow.
<ec^>
Now, you already know (because we *arrived* at that example from an earlier one using functions), that that can be transliterated into traditional function-calls:
<ec^>
function B(arg) { it = complex_operation(arg); return it }
<ec^>
function A(n) {
<ec^>
it = B("Akshat")
<ec^>
print(it)
<ec^>
}
<ec^>
... but if I modify the continuation-version slightly ...
<ec^>
function C($return, arg) { it = complex_operation(arg); $return(it) }
<ec^>
function B($return, arg) { C($return, arg); do_some_other_stuff(arg); }
<ec^>
function A(n) {
<ec^>
it = call_with_current_continuation(B, "Akshat")
<ec^>
print(it)
<ec^>
}
<ec^>
( might be typo'ing some stuff here, sorry, I'm trying to type code quickly to get the point across. If anything is Super Confusing, ask me, it may have been a mistake D: )
<ec^>
now we've arrived at a meaningful program that *cannot be encoded* with simple synchronous function-invocation, without re-writing the control-flow with callbacks.
<ec^>
The important thing to note here is that, by wrapping the stack-state up into a continuation, what we've *effectively done*, from the perspective of the programmer, is wrapped up *the ability to provide-a-result*!
<ec^>
That is, “I, Function-B, have been asked to do some work; but because I was given a continuation, I can *defer* some of that work to somebody else, transparently to my caller!”
<ec^>
vivan: test 123
<Hrorekr>
The way to write this in JS would be node-stye callbacks, right?
<ec^>
mmhmm
<ec^>
so, that's the high-level architectural-theoretic “why are these useful”
<ec^>
#2-wise ... in a continuationless language, the control-flow you're given is the control-flow you can use, as a programmer. If Yukihiro Matsumoto didn't choose to implement exceptions, then a Rubyist can't *use exceptional control-flow*.
<ec^>
but if you give the programmer continuations (and a little bit of syntactic tooling to mask their use), *the programmer* (or more realistically, a library/framework) can *add new control flow*. That is, you can literally `include 'exceptions.rb'` or something, and proceed to use true, exceptional control-flow in your program.
<ec^>
(This is one of the reasons lisp is so widely revered and loved: three aspects of lisp, [continuations, homoiconicity, and macros], when used together, basically give you a language that you can manipulate while you use it to an almost unreasonable extent. Ask me more about that some day.)
<ec^>
er, hygenic* macros.
<ec^>
as for the #1 real-world reason ... well, that's why we have Paws.
<ec^>
take a gander at some v. old Node code, from before some of today's workarounds were developed or popular:
<ec^>
that thing where anonymous functions march off the right-hand side of the screen, as you nest callback after callback after callback inside eachother? It's not just aesthetically offensive, as a lot of people assume. That has *real architectural consequences*: you're segregating *asynchronous* operations from *synchronous* operations.
<ec^>
and crucially, once any particular API in a synchronous language is made synchronous, it can never invoke *any asynchronous operation* without being re-designed.
<ec^>
(that is, if you chose to write function `foo()` as a synchronous API, with your users typing `result = foo()`, you nor anything you consume can call any *asynchronous* APIs. And if you choose the other way, that is, your users type `foo(function callback(result){ ... })` ... then the reverse applies, in that no synchronous program can ever use *you*.)
<Hrorekr>
ec^, that code is very hard to read
<ec^>
hahahaha yes it is, yes it is.
<ec^>
Now, to be fair, there are some synchronous patterns based on the event-loop that have *helped* with some of this: things like promises, etceteras. But I'd argue (and this is a conversation for another time) that those aren't *real* solutions, they're approximations, patches, workarounds. The root problem is that JavaScript is a purely-synchronous language
<ec^>
in the way that Haskell is a purely-functional language.
<ec^>
*all of the other concerns* put aside, here's the difference between a language with continuation support, and a language that has to use callbacks:
<ec^>
er, sorry
<ec^>
here's the difference *when performing asynchronous tasks*:
<ec^>
before;
<ec^>
op {
<ec^>
after;
<ec^>
}
<ec^>
... versus ...
<ec^>
before;
<ec^>
after;
<ec^>
op;
<ec^>
continuations let you put asynch tasks on an equal control-flow footing with apparently-synchronous tasks.
<ec^>
okay. All of that was a bit philosophical. My bad, I let myself get a bit ranty. (I love JavaScript, but sometimes, I really hate it. :P)
<ec^>
Hrorekr: Any technical questions on the above? I want to dive back into explicit-vs-implicit CPS, which was originally the point of all this :P
<Hrorekr>
makes sense
<ec^>
before I continue, do you see *how* continuations give you `a; b; c;`, whereas without them, you have to structure it as `a; b{ c; }`?
<Hrorekr>
but are there any cases where you might absolutely need to be synchronous?
<ec^>
rephrase
<Hrorekr>
cases where async approach is bad
<ec^>
hmmm
<ec^>
That very much depends on how you define bad.
<Hrorekr>
things would break if not done in order
<ec^>
Any *asynchronous* approach can, by definition, devolve into a synchronous operation internally; but not vice-versa.
<Hrorekr>
ah, I see
<ec^>
Ahhhhhhhahah! I like you, you're smart, this is fun
<ec^>
So what you're talking about is concurrency and/or parallelism.
<Hrorekr>
yeah
<ec^>
First off, I should point out that, no: in our above examples, although *asynchronous*, everything is still *strictly ordered*.
<ec^>
That is, it's not parallel in any way.
<Hrorekr>
oh
<ec^>
Alllll that cool stuff about data-locking and races and paralellism and blahblahblah doesn't come into play at all, because we're basically just talking about a *flow of control*, not whether the things along that flow are ever *simultaneous*.
<ec^>
at least, doesn't come into play *yet*.
<ec^>
Here's a thought-experiment:
<ec^>
`before() ; do_it({ after() })`. (a slight re-formatting of our a;b;c example above.)
<ec^>
let's imagine that do_it() is hitting the network somehow, preforming some long-running task.
<ec^>
*none of our examples* require parallelism to be defined, or to exist: these can exist entirely within a single-threaded environment.
<ec^>
*all* we're saying is “do before; then do do_it; and *when do_it is done*, do after.”
eligrey has joined #elliottcable
<ec^>
that last clause, ‘then when done, do after’ could happen many seconds later, even minutes, for all that code cares. That code does *not* guarantee that anything else gets done during those minutes.
<ec^>
this is the difference between an asynchronous system, and a truly concurrent system:
<ec^>
despite the awkward callback syntax required by its use of a call-stack, JavaScript *can* be asynchronous, if you jump through those hoops.
<ec^>
It cannot, however, ever be truly concurrent; that's an entirely different bag of worms.
<Hrorekr>
aha, so in an asynchronous system things can happen independent of each other but still in order
<ec^>
(it *can* be parallel, and that's a whole other bag of worms; JavaScript has what is called ‘cooperative threading’, which is not true concurrency, which is known as ‘preemptive threading.’)
<ec^>
mmhmm
<Hrorekr>
kind of makes sense
<Hrorekr>
if a previous function didn't give any data, the next function cannot do anything
<ec^>
So, ignoring true concurrency (the kind of parallelism where you have to worry about data-races and locking and all that jazz) for a moment, let's talk about asynchronicity and parallelism:
<ec^>
that is, basically, Node's (or Ruby's `EventMachine`, if you've used that) innovation:
<ec^>
We can get *parallelism* and *asynchronicity* (but not concurrency!), by giving control of the entire program over to a central ‘event loop.’
<ec^>
the event-loop is basically, a recurrent stack-dropping: where you never let your *stack* get too deep, because all of your functions *return* relatively early, and opt to throw their consequences onto the event-loop (using callbacks) instead of onto the stack (using function-invocation).
<ec^>
if that groks? I hope it does? sorry, that explanation was really dense.
<ec^>
There's downsides, which basically are what we've been talking about this entire time: although an event-loop lets you do asynchronous tasks, it forces segregation: because the stack is wiped out between each ‘tick’, you can never use the language's natural “return” feature from within an asynchronous operation. The stack that *scheduled* the
<ec^>
operation is long-gone when the operation completes; and it is this pattern that forces that ‘segregation’ I mentioned earlier.
<ec^>
thus you have to resort to awkward callbacks, promises, etceteras: all of these are, to be a bit prejudiced ... basically *awkward imitations* of the fall-forward semantic we've been slowly exploring this entire time.
<ec^>
Ranty again.
<Hrorekr>
yeah, makes sense
<ec^>
I care deeply about this topic, rather obviously. I guess that's why I've wasted six years of my life trying to improve on it. :x
<ec^>
so!
<ec^>
let's examine some other Cool Control-Flow Things™ related to continuations
<ec^>
Hrorekr: so, yes, taking a gander right now, but I believe modern JS's generators *are* coroutines.
<ec^>
ah, no, they're asymmetric. damnit.
<ec^>
okay, so, high-level overview: a true coroutine is either [*generators* that can talk to eachother], or [*continuations* restricted to ‘returning’ to specific points.]
<ec^>
let's talk about asymmetric coroutines, or generators, for a second.
<ec^>
Hrorekr: you already know of JS's generators, then?
<ec^>
hold on, saving a paper on coroutines to my pinboard, lol
<purr>
lol
<Hrorekr>
ec^, not really
<Hrorekr>
I have used them in python but at that time I didn't know what the hell was I doing
* ec^
nods
* ec^
scratches head
<ec^>
okay.
<ec^>
B(n) { return do_stuff(n) }
<ec^>
val = 123
<ec^>
A {
<ec^>
return val
<ec^>
val = B(val)
<ec^>
}
<ec^>
synchronous, stack-based function-invocation example again. Very simple.
<ec^>
let's look at what this control flow *looks like*, if we run the program:
<ec^>
(hm, let's rename do_stuff() to increment(). my bad.)
<ec^>
• A()
<ec^>
• B(123)
<ec^>
• A(124)
<ec^>
obviously, in a stack-based language, the second A() isn't *actually an invocation*; but it's effectively the same thing: part of A's code is being evaluated, with *new information*: in specific, that information is the integer `124`.
<ec^>
The *second part of A*, which you may now be recognizing as a conceptual coroutine, is being parameterize by the `return` invocation: as we saw before, `return 124` is effectively equivalent to `$return(124)`, an invocation of an invisible continuation.
<ec^>
Nothing groundbreaking here. Let's look at another boring example:
<krainboltgreene>
Woo stack based langauges! Go Forth!
<ec^>
krainboltgreene: ... not that sort of stack-based.
<ec^>
idk I try to keep things in channel but sometimes it's too long to paste
<ec^>
so, in this example, the control-flow is still very simple:
<ec^>
- A()
<ec^>
- B1(31)
<ec^>
- A(32)
<ec^>
- B1(32)
<ec^>
- A(64)
<ec^>
- B1(64)
<ec^>
- A(8)
<ec^>
crap. B2 / B3, there.
<ec^>
So, a coroutine is very simple: it is a single function that can be *invoked multiple times*, and can *return multiple times*; and each time it is invoked, it resumes evaluation from the *last* place it returned from.
<ec^>
(this sort of returning is called ‘yielding’ in the literature, but I'm just going to keep calling it ‘returning.’ ¯\_(ツ)_/¯)
<ec^>
(How the fuck does hastebin decide on a language ... the last one it thought was CoffeeScript, this one it thinks is Scala. o_O)
<Hrorekr>
ec^, yep
<ec^>
just like with our continuation examples before, we can use |this| syntax to demonstrate what a coroutine ‘looks like’:
VanguardVivian has quit [Ping timeout: 240 seconds]
<ec^>
after the first time `B()` is invoked, it ‘returns’ to `A` again, and is thus frozen like this:
<ec^>
{{ val = |return increment(n)|; val = return double(n) ... }}
<ec^>
this means that the *next* time it is invoked, the argument that it is given will “go into that hole”:
<ec^>
{{ val = |32|; val = return double(n) ... }}
<ec^>
now, this is obviously a super-trivial example: for instance, A() doesn't even *do any work here*, it just keeps invoking B() over and over.
<Hrorekr>
gotcha
<ec^>
hopefully, you can see some of the things that it *could* be doing.
<ec^>
now, these are called ‘asymmetric’ coroutines, or generators, and are the less-powerful version thereof: Unlike, say, a continuation (or a true coroutine), the `return` operation in the above examples *only returns to one place*: the original caller.
<ec^>
As it turns out, generators are trivially translatable to normal function application/invocation; so other than a nice clean syntax for some tasks, you don't actually gain much here. This is why JS generators don't excite me very much.
VanguardVivian has joined #elliottcable
<ec^>
(To put it another way, all of this is still happening on the stack.)
<ec^>
as evidenced by:
<ec^>
- A()
<ec^>
- B(31)
<ec^>
- A(32)
<ec^>
- B(32)
<ec^>
- A(64)
<ec^>
- B(64)
<ec^>
- A(8)
<ec^>
see, it's functionally no different than our example using function-invocation: B() is *always* “below” A(), and thus this can be executed on the stack.
<ec^>
now, where coroutines get Rly Cool, is when you have what are called ‘symmetric’, or true, coroutines:
<ec^>
in this version, our `yield` keyword (which I will now call `yield`, to differentiate it from the generator-yield of JavaScript and friends, which is what we're using above as `return`) *can return to any other invokable*.
<ec^>
(starting to remind you of continuations, yet?)
<ec^>
oh lord
<ec^>
Hrorekr: tons of typos in those examples above. Meant `increment(val)` instead of `increment(n)`, etcetcetc.
<ec^>
hope those didn't trip you up. >,>
<ec^>
so, imaginary example of a true coroutine:
<ec^>
this is going to get super-powerful, Hrorekr, so, full attention. I want you to examine it in detail and come back to me with observations.
<ec^>
In this syntax, we're declaring that `self` is a keyword to generate ‘the coroutine for the current procedure.’
<ec^>
arbitrary syntax to convey the concept; hopefully, that's not a confusing practice. (We'll be making up a lot of syntax to talk about concepts in the future ...)
<ec^>
notice that $yield, in our coroutines, is like $return from yesterday's examples for continuations? it's an “invokable”, like a function; but unlike a function, the expression `$invokable()` doesn't evaluate to a value *when a function returns* from further down the stack; instead, it evaluates to a value *when the coroutine is resumed with a value*.
<ec^>
Hrorekr: Can you follow that code?
<Hrorekr>
yes
* ec^
grins
<ec^>
good good!
<Hrorekr>
I got what it does from the code
<Hrorekr>
but I am trying to parse what you wrote
<Hrorekr>
lol
<purr>
lol
<ec^>
so, coroutines are a little less flexible, in terms of control-flow, than raw continuations;
<ec^>
but in my opinion, they're *much* more easy to understand and follow, when used in the real world.
<ec^>
and they enable nearly as many clean control-flow patterns as raw continuations.
<ec^>
Now, as I mentioned before, you can *implement* coroutines in terms of continuations: this should be pretty obvious (for instance, in lisp, I imagine it would be pretty easy to *write* that `self` keyword from within lisp, as a macro around call/cc.)
<ec^>
Hrorekr: k, just copy-paste lines of my writing that were confusing, I can rephrase.
<ec^>
easier than you staring at them blankly in confusion. :3
<Hrorekr>
I got it
* ec^
nods
<Hrorekr>
you are basically saying that instead of a return you keep passing the data to yields
<ec^>
Hrorekr: Your call: want me to move on, or is there something with regards to continuation / coroutine control-flow you want me to elaborate on?
<Hrorekr>
right?
* ec^
nods
<ec^>
yep
<Hrorekr>
nope, all clear
<ec^>
the key obviously being that you can pass data to another coroutine's `yield`, if *you* are a coroutine, multiple times.
* ec^
nods
<ec^>
-dequeue
<purr>
ec^: <ec^> concurrency vs. parallelism
<ec^>
hm, I want to do that later.
<ec^>
-dequeue
<purr>
ec^: <ec^> implicit vs. explicit CPS
<ec^>
-queue concurrency vs. parallelism
<ec^>
so, CPS. We touched on this last night.
<ec^>
Everything you and I have been talking about today has been *explicit*:
<ec^>
we've been using `call/cc`, or `self`, or something, to *get ahold* of a continuation/coroutine, for what is otherwise a normal function, invoked normally, that is capable of returning normally.
<ec^>
If you do this *all the time* (for instance, if you write a library for which every single API endpoint does not `return`, but instead accepts a continuation/callback as an *argument* ... this is popular in JavaScript),
<ec^>
then it's called “continuation-passing style”.
<ec^>
but *implicit* CPS, is another beast entirely: this is when the language or environment Does It For You.
<ec^>
let's dispatch with coroutines for a while, and focus back on raw coroutines. Here's our last example from earlier:
<ec^>
function C($return, arg) { it = complex_operation(arg); $return(it) }
<ec^>
function B($return, arg) { C($return, arg); do_some_other_stuff(arg); }
<ec^>
function A(n) {
<ec^>
it = call_with_current_continuation(B, "Akshat")
<ec^>
print(it)
<ec^>
}
<ec^>
in this span of code, we have *three* forms of invocation, and I want to highlight each, before we move on:
<ec^>
β. `call_with_current_continuation(B, "Akshat")` – “invocation with continuation”
<ec^>
γ. `$return(it)` — “invocation *of* a continuation”
<ec^>
so, now, we're going to re-write this span in an implicit-CPS language, by turning it inside-out: all of the things that were messy in that example, are going to become simple; but the simple thing is going to become, unfortunately, messy.
<ec^>
function C(arg) { it = complex_operation(arg); return(it) }
<ec^>
function B(arg) { call_with(C, return, arg); do_some_other_stuff(arg); }
<ec^>
function A(n) {
<ec^>
it = B("Akshat")
<ec^>
print(it)
<ec^>
}
<ec^>
let's look at what's changed for each of those examples. I'll go in reverse:
<ec^>
The taking of `$return` as an explicit argument has disappeared; instead, language-support exposes `return()` as a reference to an *invisible* continuation for the caller:
<ec^>
γ. `$return()`, the invocation of a continuation stored in a variable, has been replaced with `return()`, directly using a keyword for the same purpose. No substantial change here.
<ec^>
β. more usefully, `call_with_current_continuation` is no longer necessary; because *every* function-application has been replaced with an *implicit* invocation-with-continuation, and thus has here been reduced to simply `B("Akshat")`
<ec^>
this, of course, being the purpose of implicit CPS.
<ec^>
α. now, the downside here, is that the language *blesses* one particular continuation: that is, the `return` continuation is now handled specially, and although we *could* pass along the continuation we received as a plain argument `C(return, arg)`, this would require `C` to be written to know about this: it could no longer use the `return` reference within
<ec^>
its' body (because that refers to `B`, not to `A`!), it would instead have to accept the additional continuation for `A` as an argument.
<ec^>
so, to allow for encapsulation, the language has to support ‘call-with-other-continuation’ as opposed to ‘call-with-current-continuation’: in the above example, we use this as call_with(other_continuation, target_function, argument ...)
<ec^>
Hrorekr: all of the above clear?
<ec^>
stack-based code.
<ec^>
The point, of course, and I hope this is obvious, because if not I've missed something really important ... is that now we've come full-circle and *are using continuations*, can benefit from them throughout the language, while writing code that superficially (and in terms of structure, which Matters! not just aesthetics!) resembles the original, synchronous,
<ec^>
or to sum up the last two days' discussions as briefly as possible: We replaced `{ foo(); return bar() }`, with `{ foo(); return(bar()) }`. :P
<Hrorekr>
got it
<ec^>
So. Before I tie all of this back into Paws, I suspect you want me to elaborate on the concurrency/parallelism discussion,
<ec^>
but I also want to ask how tired you are, lol.
<purr>
lol
<ec^>
because i know it's late af there.
<Hrorekr>
We can continue with other functions while still doing stuff to our data
<Hrorekr>
right?
<ec^>
rephrase.
<Hrorekr>
We can do both continuation and processing inside a function body
<Hrorekr>
if that makes sense
<ec^>
hmm. That is true, but I'm not sure of the interestingness.
<ec^>
Like, without any of the things we've talked about, you can already preform both basic-processing-operations, and invocation-of-other-functions, within a function body ...
<ec^>
unless I've misunderstood you.
<Hrorekr>
uh, I think I am not clear on this
* ec^
nods
<Hrorekr>
Lemme try
<ec^>
talk to me about what your takeaways are. Describe a *continuation object* to me: what is `$return`, in our original example, and what can it *do*?
<ec^>
(copy-pasted for ease of reference:)
<ec^>
function C($return, arg) { it = complex_operation(arg); $return(it) }
<ec^>
function B($return, arg) { C($return, arg) }
<ec^>
function A(n) {
<ec^>
it = call_with_current_continuation(B, "Akshat")
<ec^>
print(it)
<ec^>
}
<Hrorekr>
we can call that other function without making it in a way that it knows about A and B
<Hrorekr>
if that makes sense
* ec^
nods
<ec^>
that is also true, but it's not a statement of the basic operation
<ec^>
don't give me ‘how’, just give me the simplest ‘what’ that you can phrase
<Hrorekr>
a continuation object is just data that is to be passed to the other function
<ec^>
what data?
<Hrorekr>
it = call_with_current_continuation(B, "Akshat")
<Hrorekr>
"Akshat" is the data before processing
<Hrorekr>
then we applied B on it
<Hrorekr>
and passed it to C
* ec^
nods
<brr>
hey ec^
<ec^>
but to iterate my point: what C is being handed, is *the right to produce a result* to A.
<ec^>
that's what exists in the $return variable, when C is running: a `continuation`, an object that gives it a handle expressing “where do I send my results?”
<ec^>
yes? does this jive with your understanding still?
<Hrorekr>
yes
* ec^
nods
<ec^>
Okay. I think the best way to ensure this is cemented is going to be to come back to it later, slash on another day.
<Hrorekr>
ok
<ec^>
Any more repetition of the points will probably be more overwhelming than helpful if you *are* confused about some part of it.
<Hrorekr>
I'll eventually get it
<ec^>
Hrorekr: Next topic, you call it: evaluation-flow in Paws, or stepping aside into a discussion of concurrency?
<Hrorekr>
let's keep it to this much for today
<ec^>
haha, somebody's getting sleepy? :3
<Hrorekr>
yep
<Hrorekr>
ec^, can I ask a personal question?
* ec^
laughs
<ec^>
the channel is named #elliottcable, of course :P
<Hrorekr>
ec^, what do you do for a living?
<ec^>
-topic s/$/ || #ELLIOTTCABLE is not about ELLIOTTCABLE/
purr changed the topic of #elliottcable to: a
<ec^>
Hrorekr: I don't usually talk about it in here. Let's just say I'm extraordinarily privileged to be able to work on Paws whenever I want, right now. (=
<ec^>
I *am* looking for programming-related work, but not desperately; and I have the further privilege of being able to be picky about the jobs I want. (For me, that basically means ... nix CRUD / Rails apps, nix generic contracting. I want to build interesting, exciting, and unique software.)
<Hrorekr>
ec^, That is pretty much what I would like to do but I am not privileged(or smart rather) enough to do it
<ec^>
Oh, I'm not smart. Trust me on that.
<ec^>
There *are* truly genius people in here, I'm not one of them, lol
<purr>
lol
<ec^>
's all privilege.
<Hrorekr>
ec^, I am trying to get freelancing but I have no idea where to start
<Hrorekr>
Make some money, buy a better laptop(Macbook!) and better internet
<ec^>
she has good advice for freelancing as a dev. Much better than anything I could offer ¯\_(ツ)_/¯
<Hrorekr>
The thing is
<Hrorekr>
There are no local jobs unless you open your own compnay
<ec^>
really? that's super-surprising. What part of India?
<Hrorekr>
Central
<Hrorekr>
nothing but forests here
<ec^>
I know squat about India, but over here, we talk about India as if it's a programming-job heaven: tons of outsourced work flowing over there.
<ec^>
ah, hm. Move? That's what I tell my backwoods-united-states dev-friends: move to the big city, that's where the programming jobs always are.
<Hrorekr>
yeah, that's what people do after their degrees
<Hrorekr>
Work for an outsourcing company for shit pay
<Hrorekr>
But I don't wanna do that
* ec^
nods
<ec^>
Move to the U.S. where the pay is *ridiculously* inflated right now? :P
<Hrorekr>
H1Bs are hard to come by
<ec^>
There's a racial stereotype that indians and asians are Good At Math and Programming over here; so you probably already have a leg-up on finding a job. Especially if you have a good college degree in CS under your belt by that time.
<Hrorekr>
ec^, they are as good as any other nationality
<ec^>
Like, in *actual skill*, yes, I know that. I'm speaking as to perceptions and stereotypes.
<Hrorekr>
We just have fuck ton of people and mostly the best move out
<Hrorekr>
ec^, my college is literally called TITS
<ec^>
LOL
<purr>
LOL
<ec^>
good point :P
<Hrorekr>
They even have a tie that says 'TIT' in bold as a part of the uniform
<ec^>
Open-source will help a lot.
<ec^>
But that's kinda a crap-shoot in other ways: it's yet another ‘make your big break! get recognized!’ avenue:
<ec^>
you can't predict how well it will go for you, in relation to how much effort you put in.
<Hrorekr>
I have had some nice ideas in my mind but I don't know how to implement them
<Hrorekr>
need someone to hold my hand during the early phases
* ec^
nods
<ec^>
what kinds of things?
<ec^>
spoiler: programming-language work doesn't get you paid unless you're Very Fucking Lucky.
<ec^>
ditto compiler-design stuff, but instead of Very Lucky, that requires you to be Very Fucking Smart, so you get hired on by the V8 team at Google, or the SpiderMonkey / Rust teams at mozilla, or something.
<Hrorekr>
ec^, just simple webapps
* ec^
nods
<ec^>
Hrorekr: those should be pretty easy to start on. What do you feel is blocking you?
<Hrorekr>
ec^, actually getting my hands dirty
<Hrorekr>
I have almost zero programming experience beyond simple exercises
* ec^
nods
<ec^>
welp! *laughs* diving head-first into a programming-language interpreter will definitely give you that.
<ec^>
starting in the next few days, I'll drag you down and drown you in Paws. I don't think you'll feel very virginal after being exposed to this. :P
<Hrorekr>
hehe
<Hrorekr>
ec^, I have interest in programming languages from the linguistics side
* ec^
nods
<ec^>
me too. To me, it's interesting how humans communicate, and *fascinating* how they encode instructions.
<Hrorekr>
Wanted a BA in Linguistics but somehow I am stuck with Computer Science
<ec^>
Programs are written for other people, and only secondarily for computers to execute, after all.
<ec^>
(thx Hal Abelson)
<ec^>
christ I love him so much
<ec^>
“If we can dispel the delusion that learning about computers should be an activity of fiddling with array indexes and worrying whether X is an integer or a real number, we can begin to focus on programming as a source of ideas.”
<ec^>
“[Computer science] is not really about computers and it's not about computers in the same sense that physics is not really about particle accelerators, and biology is not about microscopes and Petri dishes... and geometry isn't really about using surveying instruments.”
<ec^>
ohhoe: I want photos of the final product
<ja>
oh my
<ja>
yeah, like Dijkstra said about telescopes
<ec^>
ja: hi!
<ec^>
ja: wanna help with Paws?
<ec^>
ja: can I teach you Paws
<ec^>
-didja? @ ja
<ja>
(though wikiquote disputes the source of that quote)
<ja>
ec^: I've accomplished nothing with my life so far, and I'm as aged as you, approximately
<ohhoe>
i just turned 30 and you're fine neither have i
<ja>
ohhoe: whoa, cool net thingamajig!
<ja>
jeez…
<ec^>
ja: do *I* look like I've accomplished anything?
<ec^>
I've not even learned a new language feature in like six years
<ja>
ec^: No. lol
<purr>
lol
<ec^>
I've just buried myself in this project nobody cares about and not looked back
<ja>
Aw, man! Really?! :<
<ec^>
I've literally completely wasted the last *six years* on a pet project.
<ja>
You can’t be serious now about not learning a new language in like six years, srsly, c’mon dude
<ec^>
Not like, parts of them. Like, done nearly nothing with myself.
<ja>
Really? I mean *really*?
<ec^>
okay, not totally; but you get my point.
<ja>
Haven’t you like… Done cool client projects in those six years too?
<ja>
I might get your point
<ec^>
Even in terms of life-stuff: I could have tried harder to start a productive career track, find cool employers doing cool things; or I could have gotten myself into a *good* school
<ec^>
but nope. github.com/ELLIOTTCABLE/paws.js is the extent of what I can show for the past six years of everyday life.
<ec^>
ja: nothing cool lol, nope.
<ec^>
I mean, this makes it sound more dire than it is: I'm *really* happy with what I'm working on, but I'm happy for weird reasons. In absolute terms? Trust me, I'm no better than you in terms of personal achievement.
<ja>
@_@
<ja>
I mean… I guess when you say it like that…
<ec^>
I'll cede your point, though; there definitely *are* insanely-amazing people in this channel. They're just not me.
<ja>
lol
<ja>
right
<ja>
I believe so
<ec^>
whitequark knows *scarily* much about *scarily* many things ... although it seems like he's neglected the social skills for it :P
<ja>
Like ohhoe
<ec^>
inimino is, well, inimino.
<ja>
lol
<ja>
Mhm…
<ec^>
I don't really know much about ohhoe; I've only followed them at a distance on Twitter for a long time, I don't know of their work.
<ohhoe>
i just like cats
<ja>
cats are great! :3
<ohhoe>
I'm hopefully going to release some video games this year though
<ja>
oh, really?
<ohhoe>
taking a computer science online course.
<ohhoe>
yeah
<ja>
sweet!
<ohhoe>
hopefully learn javascript better too
<ja>
you’ll have to! so you can help ec^ with paws.js!
<ec^>
Hrorekr: I know very little about rails, because every part I learned back when I decide to learn it disgusted me too much to continue :x
<ja>
wat did i just click
<ohhoe>
i want to learn fundamentals of WHY things happen
<ja>
Hrorekr: Ruby on Rails is great! ʘ‿ʘ
<ohhoe>
i have no syntax memorized
<ec^>
ohhoe: ‘anything about coding.’ I swear, I thought you were frontend dev.
<ja>
haha
<Hrorekr>
ec^, or anything that'll get me a job on those freelancer sites
<ja>
explain yourself, ohhoe!
<ec^>
so you're at the copy-paste-and-see-if-it-works stage of learning JS?
<Hrorekr>
what's hot these days
<ohhoe>
yet give me an existing codebase and i know what's happening and can alter it and refactor
<ja>
Hrorekr: Meteor! ʘ‿ʘ
<ohhoe>
ya pretty much
<ec^>
Hrorekr: Definitely still Rails and Node. Maybe, uh, some Clojure?
<ohhoe>
some stuff has stuck
<Hrorekr>
ec^, clojure is nice
<ec^>
ohhoe: yah, very common things to express. That's also my first experiences with PHP Back In The Day™.
<ec^>
No shame in copy-paste programming if it works.
<ec^>
Hrorekr: Oh! Didn't know you knew lisp
<ja>
PHP…
<ja>
I’m going to bed…
<ec^>
I would have written so many of those examples today in scheme o_o
<ohhoe>
ec^: even though i've been coding for 15-16 years.
<ec^>
ja: hahah, my first ever ‘programming’ was on MediaWiki
<ja>
ec^: you’re kidding me
<ja>
:X
<ec^>
and was 99% copy-and-paste; nonetheless, I built a big successful set of websites on those skills
<ec^>
ja: don't knock on the beginners!
<ja>
lol sorry
<purr>
lol
<Hrorekr>
ec^, Lisp is what got me back into programming after multiple failures at teaching myself
<ec^>
ohhoe: O_O okay now I'm shocked
* ja
started with phpBB D:
* ec^
high-fives ja
<ec^>
been there fraaan been therrreeee
<ohhoe>
i started with a cgi-bin / perl script for blogging and phpbb around 2002?
<ec^>
ohhoe: well, in all seriousness; teaching JavaScript to beginners is, like, My Schtick.
<ohhoe>
that was my first non html thing
* ja
(◕‿◕✿)
<ec^>
well, my secondary schtick after “tell anybody and everybody to write a programming language.”
<ohhoe>
before that i was a script kiddie asshole on aol
<ja>
cgi-bin, haha, awesome!
<ec^>
so if you have some time some time (heh), I'd, like, love to contribute to your fundamentals.
<ohhoe>
but i went to school for graphic design which was a huge mistake.
<ohhoe>
b/c it was a for profit that scammed me and now i have 117k in debt. but when i graduated in 2010 all my jobs were dev
<ja>
:x
<ec^>
o
<ec^>
_
<ec^>
o
<Hrorekr>
ec^, I'm up for it
<ec^>
mirrors the experiences of a friend of mine.
<ohhoe>
so i did a lot of wordpress stuff and server admin stuff and then whatever else they wanted me to do from 2010-dec 2013
<ja>
that sounds very shitty
<ohhoe>
and then i got a job at adobe behance
<Hrorekr>
ec^, teach javascript please
<ec^>
except her parents contributed, so it's not *that* deep, but ... still ...
<ohhoe>
and it was my first full javascript job
<ohhoe>
and they fucked me over
<ec^>
Hrorekr: you already know JavaScript afaict?
<ohhoe>
never mentored me
<ec^>
Hrorekr: I was just teaching you *continuations*, and you know lisp, I'm pretty sure you're fine on JS :P
<ohhoe>
had me on a codebase that was undocumented
<ohhoe>
custom mvc that overwrote vanilla js
<ohhoe>
even though i finished my work they got rid of me 2 weeks before my stocks vested
<Hrorekr>
ec^, I suck at making things from code
<ohhoe>
anyway i'm ranting
<ec^>
I mean, I'm all for mutating the global prototypes, unlike Everybody Else Around Here, but ... it's shitty to do that to a newcomer
<ec^>
oh fuuuuuck.
<ec^>
Hrorekr: yah, I'm convinced dragging you into Paws will help with that.
<ec^>
you clearly just need to be convinced that Actually Writing Big Things isn't hard ... it just involves jumping in. You're experiencing anxiety about coding more than any real inability to code, if you ask me.
<Hrorekr>
I guess so
<ec^>
wait
<ja>
ohhoe: have you met Ginni Rometty?
<ec^>
the fuck
<ec^>
SpaceX successfully recovered a rocket
<ohhoe>
ja: i work right next to her office
<ec^>
how
<ec^>
the fuck
<ec^>
did I not know this
<ohhoe>
i haven't met her but i've seen her around a lot
<ja>
ohhoe: O_O
<ja>
intriguing
<ohhoe>
ec^: the video is amazing
<ec^>
Hrorekr: I'm convinced so. :3
<ja>
ohhoe: you’ll be staying in this channel, right?
<ec^>
ja: don't ask you'll jinx it
<ja>
shit
<ohhoe>
p much ya i have irccloud so i idle in a lot of freenode channels
<ja>
ohhoe: forget what I just said
<ec^>
just always assume that everybody is 100% addicted to #ELLIOTTCABLE and will never be able to leave.
<ec^>
works, ime.
<ec^>
2:33 AM <@emilyrose> :3
<ec^>
2:34 AM <@thealphanerd> is that zoidberg?
<ec^>
2:34 AM <@emilyrose> no
<ec^>
2:34 AM <@emilyrose> it's me smiling like a fucking furry