Skip to content

Instantly share code, notes, and snippets.

@vendethiel
Created January 18, 2018 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vendethiel/5b830f94b5cf838e66c61ea629e31d0c to your computer and use it in GitHub Desktop.
Save vendethiel/5b830f94b5cf838e66c61ea629e31d0c to your computer and use it in GitHub Desktop.
[20:57:31] <Ven``> we have (potentially) a lot to discuss. Should we start by bikeshedding, discussing viable implementations, ..?
[20:59:05] <rhendric> Not sure those conversations are separable. Implementation should inform design at least somewhat. Maybe we should start with goals?
[20:59:20] <Ven``> OK, fair enough.
[20:59:37] <rhendric> As in, is this the beginning of an eventual full support of types in Flow and/or TypeScript format?
[20:59:46] <rhendric> Is this a stopgap measure to make things a little more usable?
[21:00:03] <rhendric> Something else or in between?
[21:00:24] <Ven``> Definitely full support. Though not necessarily in the very beginning.
[21:00:57] <Ven`> I don't mind if I don't get e.g. object types and class types in the early beginning.
[21:01:03] <Ven`> Inference itself would help alleviate that
[21:01:31] <rhendric> Ideally, yes.
[21:02:01] <Ven`> For now, I want to get types on function args/function returns/let/var/const.
[21:02:17] <Ven`> simple types and generics.
[21:02:31] <rhendric> But we should also keep an eye on the rest of what we eventually want to support, in that case.
[21:02:42] <Ven`> Oh, definitely.
[21:02:56] <Ven`> it's tough. the syntax baggage of LS is... quite heavy
[21:03:02] <rhendric> Yes, that.
[21:03:13] <Ven`> I'd be interested if we could come up with a way to type objects that's not hell to parse.
[21:03:22] <rhendric> So.
[21:03:26] <Ven`> (and doesn't require to do it all in a @do-ascr in the lexer...)
[21:03:43] <rhendric> A lot of these things become much easier if we go full Haskell and separate types from values entirely.
[21:04:11] <Ven`> We definitely should, but I don't see much we need to do to get that..?
[21:04:30] <rhendric> There are some usability issues with that, clearly, but if we eventually want to support the moving target that is ‘anything that TypeScript/Flow support’, I think that's our best bet.
[21:05:18] <rhendric> Not much we need to do, agreed.
[21:05:19] <Ven`> What are the issues you're thinking of?
[21:05:22] <rhendric> Well, not as much.
[21:05:45] <rhendric> When I say separate, I mean no `(a :: A) :: B => a-to-b a`.
[21:06:01] <rhendric> Instead `f :: (A) -> B`
[21:06:10] <rhendric> `f = (a) -> a-to-b a
[21:06:17] <Ven`> OK. So really full Haskell.
[21:06:35] <rhendric> Yeah.
[21:06:38] <Ven`> it makes some stuff neater. It makes some stuff harder.
[21:06:43] <Ven`> How do you spell a let with types?
[21:06:48] <Ven`> How do you spell a typed instance variable?
[21:06:58] <Ven`> How do you spell a ES6-class-like method?
[21:08:02] <rhendric> let: not sure if necessary?
[21:08:17] <rhendric> But if necessary, ascription inside the let block, I guess.
[21:09:03] <rhendric> Maybe TypeScript isn't as good as Flow is in letting stuff like that be implicitly typed.
[21:09:41] <rhendric> typed instance variable: inside an LS class, just add a declaration.
[21:09:47] <Ven`> I think it's not as good, but I'd rather target TS than Flow, TBH.
[21:09:53] <Ven`> It seems like the community picked a side...
[21:10:06] <Ven`> (Windows support played a huge part there IMHO)
[21:11:01] <rhendric> I think in communities that use React at least, Flow is still dominant.
[21:11:27] <rhendric> Possibly others, although it's hard to see past the bias of my own experience.
[21:11:39] <Ven`> Same for my echo chamber :-).
[21:12:58] <rhendric> Anyway, you think TypeScript would require a function declared and used only once to have explicit types on its parameters to be typed inside?
[21:14:52] <Ven`> https://imgur.com/a/felN9
[21:15:00] <Ven`> yup.
[21:15:20] <rhendric> Gross.
[21:15:36] <Ven`> they probably do that for "backwards compat reasons"
[21:15:56] <rhendric> Probably.
[21:16:10] <rhendric> It makes sense given the gestalt I have of TS philosophy, but still.
[21:16:36] <rhendric> It makes our work really difficult, because what if there are other instances of LS constructing code that TS would need to have annotated?
[21:17:15] <Ven`> I think it does objects correctly.
[21:17:33] <Ven`> though we need a way to write union&intersection types. that goes for both flow & TS
[21:17:43] <Ven`> (I think we both agree Flow is superior to TS, it's just about the size of the community
[21:17:46] <Ven`> )
[21:17:47] <rhendric> What about LS's util functions?
[21:17:55] <rhendric> Will things like in$ need to be annotated?
[21:18:23] <Ven`> Tough call. Probably? This is where flow comments would prove useful, I suppose...
[21:18:33] Ven` doesn't want to introduce yet another compiler flag like --types
[21:18:43] rhendric doesn't either
[21:19:15] <rhendric> Times like this, that babel backend would really come in handy.
[21:19:29] <Ven`> Yup, I was really thinking the same :-P.
[21:20:16] <Ven`> Having a sane AST and a sane codegen would help as well
[21:20:19] Ven` mourns CSR for a bit
[21:20:42] <Ven`> I havn't looked at livescript-next too much, actually. Anyway, that's enough disgression.
[21:21:02] <Ven`> so, I'll do some digging to see if TS is able to infer anything at all.
[21:21:32] <Ven`> https://www.typescriptlang.org/docs/handbook/type-inference.html seems like it does bottom-up type derivation
[21:21:37] <Ven`> but no further "type inference"
[21:21:54] <Ven`> That's an issue with your proposal, I think, I don't really want to have to name all the functions I'm going to type.
[21:22:07] <Ven`> I mean, an issue with the Haskell-style declare-then-define
[21:22:25] <rhendric> Yeah. Like I said, usability issues.
[21:22:39] <rhendric> I know it's less powerful than the alternative.
[21:23:10] <rhendric> I'm just not sure the more powerful thing can be made compatible with LiveScript's syntax without creating a messy headache.
[21:24:31] <Ven`> "more powerful thing" being?
[21:24:51] <rhendric> ‘Mixfix’ type annotations.
[21:25:06] <Ven`> you mean infix :: or @: ?
[21:25:11] <rhendric> Yeah.
[21:25:34] <rhendric> Along with whatever we do for return types for functions.
[21:29:50] <Ven`> So you'd propose to still do it the Haskell way and all?
[21:32:03] <Ven`> I don't think that way would make the feature that useful to me.
[21:32:23] <Ven`> ....unless we go totally crazy and re-introduce `where` and allow type annotations there :P. Full haskell indeed.
[21:32:47] <rhendric> Ha, yeah, that seems off the table.
[21:32:55] Ven` wouldn't be against reintroducing where, but that's another issue altogether!
[21:32:58] <rhendric> If it's not useful, then no point in trying to do it that way.
[21:33:23] <Ven`> well, the haskell way would mean that for e.g. every .map I want to write needs a declared function.
[21:33:36] <Ven`> That's a verbosity LS has not used me to :P.
[21:34:13] <rhendric> The prospect of `complicated LS expression with (complicated destructuring :: complicated type) :: more complicated type -> function body` freaks me out a little.
[21:34:43] <Ven`> no, no, I think that's a non-goal.
[21:34:59] <rhendric> Yeah, I was operating on the assumption that little map one-liners could be inferred by the type checker, but I guess that won't work for TS.
[21:35:01] <Ven`> You don't write `{a :: number} = x`. That's one case where both TS and Flow do the right thing.
[21:35:49] <Ven`> https://imgur.com/a/ArmSM
[21:35:57] <Ven`> (it doesn't show b's type because it's not selected)
[21:36:34] <rhendric> So: let's annotate `objs.map(({ a, b }) -> (x) -> a*x + b)`
[21:36:36] <Ven`> actually this is a better example: https://imgur.com/a/KI0wI
[21:37:15] <Ven`> Proposed:
[21:38:28] <Ven`> https://gist.github.com/vendethiel/49ff86793d796c535e45de75ddc58f62
[21:40:34] <rhendric> For that matter, maybe:
[21:41:03] <Ven`> (we don't do anything with `type`, we just translate it to an alias. Hopefully those look the same for TS and Flow....)
[21:41:12] <rhendric> type f = Function { a :: number, b :: number }, Function number, number
[21:41:36] <rhendric> objs.map(({ a, b }) -> (x) -> a*x + b :: f)
[21:42:08] <rhendric> And *then* we can replace Function with -> without conflict :-).
[21:42:09] <Ven`> uhhh... parsing f there to be the whole function's type is gonna prove **difficult**
[21:42:16] <rhendric> Is it?
[21:42:22] <rhendric> Just give :: very low precedence?
[21:42:38] <Ven`> precedence isn't gonna matter, we added parentheses there.
[21:43:08] <Ven`> (also my progress on :: was further stalled because <<< might be somehwere rewritten to ::, I didn't check again)
[21:43:41] <rhendric> (Whatever, mentally replacing :: with @: if necessary isn't a big deal I don't think.)
[21:43:52] <Ven`> (I just wanted to make a comment about it)
[21:43:57] <rhendric> I don't understand what the problem is still.
[21:44:12] <Ven`> The problem for a :: there?
[21:44:54] <rhendric> I guess? Is that the problem?
[21:45:40] <Ven`> first off, it potentially conflicts with casts. Second, it's not clear which function it applies to. Third: we rewrite `(x) -> (y) -> x + y :: f` to `(x) -> ((y) -> (x + y.prototype(f)))` before the parser ever sees it.
[21:45:46] <Ven`> So there's nothing about "precedence" etc to be applied.
[21:47:22] <rhendric> That rewrite can be made to stop at ASCR tokens, can't it?
[21:47:26] <rhendric> What's the cast conflict?
[21:47:30] <Ven`> also I don't see how we'd compile your code, outside of a cast?
[21:47:46] <Ven`> the cast conflict: well, we might want a + b :: Int to mean `(int)(a + b)`
[21:48:03] <Ven`> The rewrite can be made to stop at ASCR tokens, but then how do you type only the inner function?
[21:48:06] <rhendric> Oh, does TS allow that?
[21:48:21] <Ven`> I think so. At least there's a "x as Type", swift-like
[21:48:27] <Ven`> (or c# like rather)
[21:48:32] <rhendric> With Flow, you can only (upcast? downcast? Whichever one is the safe one) that way.
[21:48:47] <Ven`> it depends on the type's variance :-)
[21:49:16] <rhendric> You type only the inner function by adding parentheses, if you want.
[21:50:25] <Ven`> it still seems to me like we lose reading comprehension there. By putting the important infos on the wayside
[21:50:46] <rhendric> A little, sure.
[21:51:11] <rhendric> But your way, the arrow rewriter in the lexer has to jump over the Function Int Int before it gets to the PARAM( rewriting it needs to do.
[21:51:35] <Ven`> that's not my way, that's your way ;-0
[21:51:38] <Ven`> my way is with [].
[21:51:51] <rhendric> Ooookay, sure.
[21:52:19] <rhendric> So if we go full Scala, we now have two different ‘expression’ languages in LiveScript.
[21:52:54] <rhendric> And how do you notate tuples? A `Tuple` special type constructor like `Function`?
[21:53:21] <Ven`> TS doesn't have tuples
[21:53:33] <Ven`> oh, they do actually
[21:53:57] <Ven`> they write [a, b], huh. How is it in Flow?
[21:54:01] <rhendric> Same.
[21:54:13] <Ven`> I'm surprised they didn't go for the "obvious" (a, b)
[21:54:15] <Ven`> Okay.
[21:55:01] <rhendric> I have to go in a few minutes; is there a nice place to conclude this?
[21:56:20] <Ven`> Well, from reading this, apparently not
[21:56:36] <rhendric> I think we've agreed that both TS and Flow should be targets; that we want to support everything possible eventually; and that a pure Haskell-like approach isn't viable (but maybe something that is almost that approach with some very simple infix :: support is?).
[21:56:43] <rhendric> Other than that, a lot of unknowns and maybes.
[21:57:34] <Ven`> https://gist.github.com/vendethiel/ae15873a428627de640a32cdefe83ce2 is really not that bad.
[21:57:43] <Ven`> We could have :: (Int -> Int), if we force parentheses to be used.
[21:57:47] <Ven`> I think that's totally viable
[21:58:02] <Ven`> ... but we need to make -> lookbehind more complex, yet again.
[21:58:19] Ven` didn't realize it had already been an hour...
[21:58:59] <rhendric> I personally am willing to give up a fair amount of visual appeal in order to have the lexer not get more complex.
[21:59:34] <Ven`> actually no, I'm totally wrong.
[21:59:41] <Ven`> @parameters doesn't need to be made any more complex.
[21:59:55] <Ven`> We also have the option of ASCR doing some parsing. Like a sub-language, much like literals or regexes.
[22:00:04] <rhendric> I have to go.
[22:00:14] <rhendric> I'll happily review any further POCs you want to invest in.
[22:00:23] <Ven`> I suppose on the issue tracker
[22:00:30] <rhendric> You've heard the objections I anticipate making.
[22:00:48] <Ven`> aye.
[22:01:02] <rhendric> Okay, good hunting!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment