06:14 | <devsnek> | https://es.discourse.group/t/triple-backtick-template-literal/337/2 |
07:30 | <Bakkot> | "indentation in template literals is sometimes ugly" does not seem like it warrants adding a fourth kind of string literal, on its own |
13:59 | <devsnek> | I wonder if proper const references could be implemented performantly |
14:00 | <devsnek> | references/variables whatever |
14:18 | <bradleymeck> | what do you mean |
14:34 | <devsnek> | bradleymeck: like `superconst x = {}; x.a = 1` throws an error |
14:36 | <devsnek> | in my mind specifying this behaviour would be pretty easy but i'm not sure about the performance for actual impls |
14:36 | <bradleymeck> | so any reference with a base of `x` would error if you tried to use a mutation operator (since getters can mutate :shrg) |
14:36 | <devsnek> | yeah you basically just mark the references |
14:36 | <devsnek> | and marked references create new marked references |
14:37 | <bradleymeck> | wouldn't it be able to find that during codegen? |
14:37 | <devsnek> | so even if you did `const y = x; y.a = 1` it would throw |
14:37 | <bradleymeck> | oh, well... thats mmmm |
14:37 | <devsnek> | yeah that part i think makes codegen slightly hard |
14:37 | <devsnek> | although i wonder |
14:37 | <devsnek> | `const y = (() => x)()` |
14:38 | <devsnek> | that would clear the marker |
14:38 | <bradleymeck> | that would add a branch to each op on any potentially non-local ref which seems... no bueno |
14:39 | <bradleymeck> | cause you also get into strange things like `let x = {}; superconst y = x; x = y; x.z = 1//?` |
14:40 | <devsnek> | maybe just allowing that to not throw is reasonable |
14:41 | <devsnek> | not like this is a security feature |
16:21 | <ljharb> | https://npmjs.com/dedent exists, why does it need syntax? |
16:27 | <devsnek> | ljharb: i think its useful enough to be built in, and you can't tag an already tagged template |
16:31 | <bradleymeck> | stares at https://twitter.com/garybernhardt/status/1260668609837187073 |
16:34 | <devsnek> | lul |
16:35 | <Bakkot> | I'd be fine with shipping a builtin dedent API |
16:36 | <Bakkot> | you can make it compose with other template tags: dedent(fn) could return a tag which does dedenting and then invokes fn |
16:36 | <Bakkot> | though it's a little non-obvious what the right behavior is there, since interpolated strings might themselves contain linebreaks and indentation |
16:36 | <Bakkot> | probably you just assume they don't, though |
16:37 | <ljharb> | Gary’s using it wrong tho :-) |
16:38 | <ljharb> | it’s not meant to be called as a function |
16:38 | <devsnek> | it is |
16:39 | <devsnek> | in the example on the npm page |
16:39 | <Bakkot> | yeah that's explicitly one of the things it supports |
16:39 | <devsnek> | in any case |
16:40 | <devsnek> | i think almost every template literal i've ever written that spans multiple lines |
16:40 | <devsnek> | has this indentation problem |
16:41 | <devsnek> | i can only imagine people liking this feature |
16:41 | <ljharb> | yeah that’s fair |
16:41 | <ljharb> | I’d like it too, but it doesn’t seem worth the cost |
16:41 | <devsnek> | what cost |
16:42 | <Bakkot> | seems worth it as an API |
16:42 | <Bakkot> | not as syntax |
16:42 | <Bakkot> | syntax is expensive |
16:42 | <devsnek> | this seems pretty simple in terms of both implementation and human understanding |
16:42 | <Bakkot> | it is still something you are making everyone who learns the language learn |
16:42 | <Bakkot> | that is expensive |
16:43 | <devsnek> | it seems more than worth it from my perspective |
16:44 | <Bakkot> | /shrug |
16:44 | <Bakkot> | you are welcome to present to the committee |
16:45 | <Bakkot> | but I would wager extremely good odds that most people will agree it is not worth it as syntax |
16:55 | <Bakkot> | I have a rule of thumb about syntax, which is that it should either be taking something which is common and awkward to do without syntax and making it easy, or taking something which is effectively impossible and making it possible |
16:56 | <Bakkot> | dedenting can be done as without syntax very easily, though it's embarrassing that none of the popular published libraries do it right (assuming this thread is to be trusted) |
17:21 | <ljharb> | is it that it's broken in general, or only for String.raw output |
17:26 | <Bakkot> | broken in general |
17:26 | <Bakkot> | dedent('a\\nb'), which contains no linebreaks, returns `a\nb`, which does |
17:29 | <Bakkot> | (String.raw output is just normal strings you could write yourself, though, so the question doesn't really make sense) |
17:30 | <devsnek> | i think using String.raw was just to illustrate that escapes weren't being passed in |
17:34 | <ljharb> | ah k |
21:26 | <jridgewell> | I actually love this, and I highlight why this needs to be syntax in my reply on es.discourse.group |
21:27 | <jridgewell> | Having this as an API prevents you from using it as a tag |
21:27 | <jridgewell> | Eg |
21:28 | <Bakkot> | jridgewell: you could make "String.dd(tag)` contents `" do the right thing though |
21:29 | <Bakkot> | i.e. String.dd(fn) would return a function which wrapped `fn` and passed it the same things it would have been passed if it had been used as a tag directly, except dedented |
21:30 | <jridgewell> | https://www.irccloud.com/pastebin/eZtDzhud/dedenting.js |
21:32 | <jridgewell> | I think making it a higher-order function is a lot more cost than adding syntax |
21:32 | <Bakkot> | ... what, why |
21:33 | <devsnek> | i think the higher order function is weirder |
21:33 | <jridgewell> | Because I hate higher-order functions… |
21:33 | <devsnek> | i'm not gonna comment on cost |
21:33 | <devsnek> | actually i will say |
21:33 | <devsnek> | its less apparent what is happening |
21:33 | <Bakkot> | jridgewell you hate... map? |
21:33 | <jridgewell> | Functions that return more funcitons is way more complex than individual functions |
21:33 | <devsnek> | map says what it is doing with the function |
21:33 | <Bakkot> | devsnek strong disagree, nothing about "```" suggests what's going on |
21:33 | <devsnek> | maybe if you call it dedentMap |
21:33 | <jridgewell> | Limiting higher-order to just fucntion-returning functions |
21:34 | <devsnek> | mapDedent(f) |
21:34 | <devsnek> | whatever fp people call these functions |
21:34 | <Bakkot> | jridgewell you hate Function.prototype.bind? |
21:34 | <jridgewell> | Yes |
21:34 | <Bakkot> | well |
21:34 | <Bakkot> | I don't think this preference ought to guide the design of JS |
21:35 | <jridgewell> | Besides `bind`, I can't think of any other higher-order in the language |
21:35 | <Bakkot> | also, though, I don't think people actually need to think about what's going on |
21:35 | <devsnek> | even if you don't know that triple backtick performs deindentation |
21:35 | <Bakkot> | you'd be like "how do I use dedent with my tag?" and stackoverflow would say "write String.dedent(tag)` foo `"instead of "tag` foo `" and you would go about your life |
21:36 | <Bakkot> | under the hood, yes, what's happening is that there is a function which returns a function |
21:36 | <Bakkot> | but that is not something people actually need to think about |
21:36 | <devsnek> | if we're considering stackoverflow a valid solution to unclear apis |
21:36 | <devsnek> | i have many things i wish to propose |
21:36 | <Bakkot> | it's not unclear |
21:36 | <Bakkot> | it's just not something you were aware of |
21:37 | <Bakkot> | we are considering "I don't know about this feature" to be something solved by stackoverflow, yes |
21:37 | <devsnek> | you can guess what `x.map((a) => a + 1)` does |
21:37 | <Bakkot> | you can guess what String.dedent`` does too |
21:37 | <Bakkot> | also String.dedent(tag)`` |
21:37 | <devsnek> | `dedent(html)` looks like gibberish to me |
21:37 | <ljharb> | it buffs out dents |
21:38 | <Bakkot> | devsnek I maintain String.dedent(tag)`` is strictly easier to understand at a glance than tag``` ``` is |
21:39 | <devsnek> | yeah i think completely the opposite |
21:39 | <jridgewell> | Same |
21:39 | <Bakkot> | nothing about ``` suggests dedenting is going on |
21:39 | <devsnek> | i care more about the tag than the dedent |
21:39 | <Bakkot> | just the opposite, to me, since ``` in _every other language_ means "exactly what's in here, raw, with no changes" |
21:39 | <devsnek> | i only know of python |
21:39 | <devsnek> | which has dedent |
21:40 | <devsnek> | but also doesn't have tagged templates |
21:40 | <Bakkot> | python has it as an API, yes |
21:40 | <Bakkot> | that being the sensible place to put it |
21:40 | <Bakkot> | instead of adding a new type of string literal to the language |
21:40 | <devsnek> | if we didn't have tags i might agree with you |
21:40 | <devsnek> | maybe we need a standard way to compose tags |
21:41 | <Bakkot> | tag composition doesn't usually make sense |
21:41 | <Bakkot> | it happens to for dedent, because dedent doesn't need to do interpolation |
21:41 | <Bakkot> | but most tags do |
21:42 | <devsnek> | what if its called dedentWithTag |
21:42 | <rkirsling> | was there prior art for tagged templates? it's still such an interesting concept to me |
21:42 | <ljharb> | rkirsling: "quasiliterals" in some language, iirc |
21:43 | <devsnek> | lol of course its elang |
21:43 | <devsnek> | mark miller is everywhere |
21:43 | <Bakkot> | devsnek I am fine with dedentWithTag + also dedent, and no overloads |
21:43 | <Bakkot> | though I don't really see what's wrong with the overload |
21:43 | <rkirsling> | I thought you mistyped erlang for a sec |
21:44 | <devsnek> | erights.org |
21:44 | <rkirsling> | does that language have users? seems weird to use personal research as prior art |
21:44 | <ljharb> | rkirsling: i mean, that's where Promise comes from. |
21:45 | <rkirsling> | o_o |
21:45 | <ljharb> | afaik E invented the concept, and other langs' Futures/Promises/etc come from that? |
21:45 | <devsnek> | every interesting feature in modern programming languages came from E or smalltalk |
21:45 | <devsnek> | don't @ me |
21:45 | <ljharb> | one of those probably used @ for the first time |
21:45 | <rkirsling> | wowsers, I've never heard of this |
21:47 | <rkirsling> | I mean the CS concept of a Future is 20 years older than that according to Wikipedia |
21:47 | <rkirsling> | er rather apparently "promise" dates to 1976, and "future" to 1977 |
21:48 | <rkirsling> | interesting |
21:49 | <devsnek> | lol mark and dean are in the wikipedia page on futures and promises |
21:51 | <ljharb> | rkirsling: promise.then(future) |
21:51 | <rkirsling> | heh |
21:51 | <devsnek> | apparently they invented the promise pattern that js promises are based on |
21:53 | <rkirsling> | that's pretty amazing, to be on the first-ish implementation end of something that propagated to every language |
21:54 | <ljharb> | quite the personal research :-p |
21:55 | <devsnek> | i think i came up with a novel way of storing some data structure at some point |
21:55 | <devsnek> | i think it was tree related |
21:56 | <devsnek> | oh it was unicode character name mapping |
21:56 | <devsnek> | i hope i still have that code |
21:56 | <rkirsling> | I mean, "personal" aside, it does seem to be a matter of research? if I'm following correctly |
21:56 | <rkirsling> | but I guess it sounds like the more literal meaning would've been by Liskov in the 80s: https://en.wikipedia.org/wiki/Argus_(programming_language) |
21:57 | <rkirsling> | oops nope |
21:57 | <rkirsling> | "It seems that promises and call-streams were never implemented in any public release of Argus,[16] the programming language used in the Liskov and Shrira paper." |
21:58 | <rkirsling> | and then the Xanadu implementation is claimed to be "independent" |
21:58 | <rkirsling> | of that |
21:59 | <rkirsling> | so it's definitely research if you're inventing new (mini-)paradigms |