Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Start working on type ascriptions #803

Closed
wants to merge 1 commit into from
Closed

Conversation

vendethiel
Copy link
Contributor

I would like everyone's input on this: the syntax, what we're compiling to, etc.
The idea is to compile down to TS or flow-compatible stuff

@heavyk
Copy link

heavyk commented Dec 30, 2015

could you give an example? I'm not sure I understand

@robotlolita
Copy link
Contributor

So, basically:

(a @: Type, b @: Type) -> ...

Gets compiled to:

(function(a : Type, b : Type){ ... })

Is the idea to support things like TypeScript or Flow?

@vendethiel
Copy link
Contributor Author

Yes, indeed. I'll make this clearer.

@robotlolita
Copy link
Contributor

Ah. I'm not particularly fond of the @: symbol, but I also can't think of any other that is available and denotes a typing relationship well :(

I like the idea of compiling to TS/Flow though :3

@vendethiel
Copy link
Contributor Author

Right? : and :: both doesn't work, so... I went for the one I could think of.

@heavyk
Copy link

heavyk commented Dec 31, 2015

oh, I see now. yea, I like the idea of compiling to TS/flow.

could this work?

fn = (:a Type, :b Number) ->

@vendethiel
Copy link
Contributor Author

It'd make the lexer a bit more complex, which I'm not too fond of. But I'm open to opinions.

@robotlolita
Copy link
Contributor

An alternative might be using the same symbol Clojure uses to declare types. It's reusing a symbol, but I don't think that's an issue for argument names:

foo = (a ^Type, b ^Another-Type) ^ReturnType -> ...
foo = (a ^Type = ^clone) -> ...

@vendethiel
Copy link
Contributor Author

Yeah, but it's currently parsed as an infix MATH (power) :/

@vendethiel
Copy link
Contributor Author

At least, the fact our unary clone got changed to ^^ helps (because we allow unary ops there)

@waynedpj
Copy link

waynedpj commented Jan 1, 2016

Right? : and :: both doesn't work, so... I went for the one I could think of.

is there any interest in making some breaking changes to free up operators like : and :: that many already recognize as defining types, particularly : used in TypeScript+Flow? IMHO the type ascriptions would take precedence over most other uses of operators.

also, even the Livescript homepage seemingly uses :: for type ascriptions (in the 'Programmatic API' section):
LiveScript.compile(code :: String, options :: Object?) -> String

finally, there already seems to be some discussion on removing duplicated/etc. functionality:
#219
#721

peace

@vendethiel
Copy link
Contributor Author

We can change the docs, that's very minor. It currently just mimics Haskell's syntax :-).

You're free to ping those issues to try and get some tractions ;-).

@gkz
Copy link
Owner

gkz commented Jan 2, 2016

(x :: Number) ->

Seems to be a syntax error - maybe we could just support the syntax for function definitions?

@vendethiel
Copy link
Contributor Author

Problem is just the lexer's complexity. We need to resort to per-nest flag (or something) to parse correctly (a :: Foo = -> ::) ->, say

@vendethiel
Copy link
Contributor Author

Urgh, https://github.com/gkz/LiveScript/blob/master/test/cs-classes.ls#L289 doesn't parse correctly. Obviously. I guess I need to change the regexp to @:(?!:)...

@heavyk
Copy link

heavyk commented Jan 6, 2016

ok, if you don't like the atom syntax, what about c++ syntax?

lala = (a<Type>, b<Number> = 3) -> ...

@vendethiel vendethiel mentioned this pull request Jan 12, 2016
8 tasks
@rightfold
Copy link

a isa number

@igl
Copy link
Contributor

igl commented Jan 13, 2016

Arrow functions are fine and dandy but what aboot braceless function declarations?

function add : number a : number, b : number => a + b
function add @ number a @ number, b@number => a + b
function add @: number a @:number, b @:number => a + b
function add~number a~number, b~number => a + b
function add^number a^number, b^number => a + b
function add<number> a<number>, b<number> => a + b

C++ style looks best to me.

What do you guys think about type contracts like in contracts.coffee or elm?

@vendethiel
Copy link
Contributor Author

I really don't like parenless function definitions, but anyway, all the signatures will look the same.

@unclechu
Copy link
Contributor

I vote for :: it's easy to catch by eyes for me and I think this:

fn = (a :: Type, b :: Number) ->

is more obvious than that:

fn = (:a Type, :b Number) ->

@coachshea
Copy link

agreed
On Fri, Jan 15, 2016 at 06:21:01AM -0800, Viacheslav Lotsmanov wrote:

I vote for :: it's easy to catch by eyes for me and I think this:

fn = (a :: Type, b :: Number) ->

is more obvious than that:

fn = (:a Type, :b Number) ->


Reply to this email directly or view it on GitHub.*

@igl
Copy link
Contributor

igl commented Jan 15, 2016

Unfortunately :: compiles to prototype in LS.
There is also 'function-bind' a es7 proposal using :: it's only a proposal though.

@AriaMinaei
Copy link

How about declaring the function type in a separate line?

add :: (Number, Number) -> Number
add = (a, b) ->
  a + b

I think the other syntax (defining the type in the same line as declaring the function) creates too much visual clutter, and it just doesn't go with LiveScript's terse syntax, but that might be a matter of taste.

@unclechu
Copy link
Contributor

@AriaMinaei may be as alternative, but if you have a lot of arguments, inline declaration will be easier to read.

add :: (
  number
  number
  string
  boolean
  Object
  Date
  string[]
) -> number
add = (
  foo
  bar
  test
  test2
  abc
  def
  zyx
) ->
  a + b

In this case I can't say immediately what type does have test2.
And in case with inline type declaration we keep it short and readable:

add = (
  :foo   number
  :bar   number
  :test  string
  :test2 boolean
  :abc   Object
  :def   Date
  :zyx   string[]
): number ->
  a + b

@AriaMinaei
Copy link

@unclechu Correct, but how many functions would have that many arguments? A function invocation with more than five or six arguments would be a bit unreadable, unless the arguments are named (through a config object).

Also, writing type annotations in the same line as function declaration makes even simple functions like this overly verbose. I'm not even sure if that is a matter of taste.

@focused
Copy link

focused commented Feb 9, 2016

I love this one style of type declaration:

add :: (Number, Number) -> Number
add = (a, b) ->
    a + b

@unclechu I think we should not pass more than 4 or 5 arguments, in this case we should use data structures (Array, Object). Look:

count-leaves :: (Tree, BranchSide) -> Number
count-leaves = (t, s) ->
  ...

@dead-claudia
Copy link
Contributor

@vendethiel Status?

@vendethiel
Copy link
Contributor Author

@isiahmeadows still undecided on which token. Overloading :: seems risky (and hard to parse in cases like (a = -> x::) ->, say).

@ghost
Copy link

ghost commented Feb 21, 2016

Maybe JavaScript types in TypeScript ?
Uses JSDoc for type information.

@dead-claudia
Copy link
Contributor

@thelambdaparty I really dislike JSDoc type annotations. They are almost a joke in their verbosity.

@rightfold
Copy link

They are almost a joke

As is TypeScript.

@dead-claudia
Copy link
Contributor

@rightfold To be honest, Java's type system are better than JSDoc annotations in my opinion. And I really don't like Java. The only thing they're worth using for are for external API documentation, and even that's disputable.

I wasn't comparing them to powerful type systems like Haskell's.

@rightfold
Copy link

Who said anything about Java?

@dead-claudia
Copy link
Contributor

I was drawing a comparison to clarify what I meant. Basically, I feel JSDoc
types would suck more than the type system of a really bad language.
Especially for a concise language.

On Mon, Feb 22, 2016, 07:49 I moved to Bitbucket notifications@github.com
wrote:

Who said anything about Java?


Reply to this email directly or view it on GitHub
#803 (comment).

@chrisfls
Copy link

So many options...

(a & Type, b & Type) -> ...
(a @: Type, b @: Type) -> ...
(a ::{Type}, b ::{Type}) -> ...
(a ::<Type>, b ::<Type>) -> ...
(a &<Type>, b &<Type>) -> ...
(a <:Type:>, b <:Type:>) -> ...
(a {:Type:}, b {:Type:}) -> ...
(a {.Type.}, b {.Type.}) -> ...

(I really like the syntax of the last two, reminds me of nim's pragmas)

@dead-claudia
Copy link
Contributor

I'm okay with any of those except the ones with ampersands (I would
consistently misread them as type union, which TypeScript isn't the only
one using that syntax).

On Tue, Feb 23, 2016, 06:30 Christian Ferraz Lemos de Sousa <
notifications@github.com> wrote:

So many options...

(a & Type, b & Type) -> ...
(a @: Type, b @: Type) -> ...
(a ::{Type}, b ::{Type}) -> ...
(a ::, b ::) -> ...
(a &, b &) -> ...
(a <:Type:>, b <:Type:>) -> ...
(a {:Type:}, b {:Type:}) -> ...
(a {.Type.}, b {.Type.}) -> ...

(I really like the syntax of the last two, reminds me of nim's pragmas)


Reply to this email directly or view it on GitHub
#803 (comment).

@kay-is
Copy link
Contributor

kay-is commented Feb 28, 2016

Do they need to be non-valid js identifiers (like : or ^ etc.)?

If they can be anything, how about § ?

§ is a bit associated with laws (which types essentially are)

my-func = (a §Number, b §String) §Boolean -> 
my-func = (a §Number, b §String) -> §Boolean 

my-func = §Boolean (§Number a, §String b)-> 

@dead-claudia
Copy link
Contributor

I would prefer ASCII symbols to denote types, BTW. And preferably, yes,
they should. I already run into issues occasionally with is and _.

On Sat, Feb 27, 2016, 19:09 Kay Plößer notifications@github.com wrote:

Do they need to be non-valid js identifiers (like : or ^ etc.)?

If they can be anything, how about § ?

§ is a bit associated with laws (which types essentially are)

my-func = (a §Number, b §String) §Boolean ->
my-func = (a §Number, b §String) -> §Boolean

my-func = §Boolean (§Number a, §String b)->


Reply to this email directly or view it on GitHub
#803 (comment).

@heavyk
Copy link

heavyk commented Feb 28, 2016

I have the § key on my keyboard and I would have suggested it also but the us kbd does not have the key. I always thought it was ascii, but upon looking - alas it is not - I guess it was one of the iso standards.

I'm also ok with whatever cept for ampersands. I suppose the clearest to my eyes is the a @: Type one

@focused
Copy link

focused commented Feb 28, 2016

I have no such key, and many of us

@heavyk
Copy link

heavyk commented Mar 1, 2016

sorry, that wasn't the point.

I suppose the clearest to my eyes is the a @: Type one

@rhendric
Copy link
Collaborator

rhendric commented May 23, 2017

I know this is a closed PR, but since @dk00 is still linking to it, it seems useful as a repository for bikeshed suggestions. Here's mine:

(a (Number), b (String)) -> ... # not sure what to do about return types though
x (foo: String || Number) = get-object-with-foo-property!

Advantage of this syntax over most of the above: it already parses into an AST, and definitely won't at least the first line probably doesn't conflict with any valid LS since you can't assign to a function call.

(Edit: made some some overconfident assertions there, huh?)

@vendethiel
Copy link
Contributor Author

vendethiel commented May 23, 2017

I'm not sure what that 2nd line describes? The : is pretty complex to parse correctly.

@rhendric
Copy link
Collaborator

Ascriptions for variable declaration.

@vendethiel
Copy link
Contributor Author

is x or foo the variable?

@rhendric
Copy link
Collaborator

x is a variable, with a type that asserts it has a property named foo with value that is a String or a Number. As elsewhere in LS, foo: String || Number is shorthand for { foo: String || Number }.

@vendethiel
Copy link
Contributor Author

Isn't this ambiguous with x((foo: String || Number) = get-foo!) (declare a variable inside a funcall)?

@rhendric
Copy link
Collaborator

Gah, yes, you're right! Righto, that's what I get for tossing off half-baked thoughts in passing.

@vendethiel
Copy link
Contributor Author

It might be better, at least at first, to only allow type ascription when using declarators (var/const) (maybe in lets as well).

@ozra
Copy link

ozra commented Sep 21, 2017

Another soft ball in the air: foo = (x ^Number, y ^String) ^String -> "#{x}, #{y}" [ed: what was I thinking].

A method I'm biased towards (used in my own lang) is that types are required to be Capitalized, while all value identifiers are required to be initial lowercase: foo = (x Number, y String) String -> "#{x}, #{y}" - that's a breakingly breaking rule in an existing language though :-/

Too bad @kay-is suggestion of § isn't us-keymap and us-charset friendly, I considered that one also for my pet lang before :-/

The Haskellish way posed earlier in the issue is a good bet too, and when non-clashing symbology can be figured out - both the inline- and pre- typedecl would be awesome imo.

@vendethiel
Copy link
Contributor Author

Well, there's always the solution of writing the type signature before the object itself, and not inline. That'd remove a good chunk of ambiguities.

@danielo515
Copy link

What is the status of this ?

@rhendric
Copy link
Collaborator

Exactly what it looks like. There's the occasional idea being tossed around in #999, if you feel like helping out.

@danielo515
Copy link

I'll take a look at that issue.
Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.