
Have: a new language that transpiles to Go - wowoc
http://havelang.org/
======
bnchrch
If I had one recommendation to increase your projects chance of success it
would be to make sure a snippet of code is shown right away. On your homepage,
on your github page, where ever you think someone will encounter the project
for the very first time.

This seems to be a common problem with programming language projects, at least
initially, so I'm not trying to berate or shame you just point it out.

Anyways it does look interesting and I'm always happy when I see python
inspired syntax!

~~~
wowoc
Thanks! Yeah, now it does seem bad that I haven't put any snippets on the
front page. I'll fix that later today.

~~~
35bge57dtjku
I really like the side by side comparisons here: [https://www.scala-
js.org/](https://www.scala-js.org/)

------
nolite
Is this a contest to find the most ungoogleable names possible? I think they
just took the lead..

~~~
ionforce
Do you have Have? You would have had Have if you could have Googled for it.
But that's okay. Having half Have is better than having no Have at all.

~~~
junke
I used to Go, now I Have.

~~~
epalmer
Or you Have to Go. Oh did I say that?

Edit: typo.

------
Lxr
The command to transpile should be havetogo :)

~~~
StavrosK
I have a feeling that's why this language has that name.

------
guessmyname
I read the name "Have" as "Haxe" [1] and thought it was a subset of their
cross-platform toolkit. I cannot think of many use cases _(a transpiler for a
system programming language)_ because Go in itself is very simple, which is
one of the main reasons so many developers from other communities have
switched, because with a short list of reserved keywords, C-like syntax, and
simplicity of its standard library people can do amazing things.

At least it will provide Generics [2] ¯\\_(ツ)_/¯

Would _you_ use a project like this? If yes, for what?

[1] [https://haxe.org/](https://haxe.org/)

[2]
[http://havelang.org/post/for_gophers/#generics](http://havelang.org/post/for_gophers/#generics)

~~~
echelon
I'm already becoming really productive in Rust, so I haven't had any reason to
really pick up Go. (We do use it at our company, but I mostly work in Java,
Ruby, and TypeScript.)

That said, the idea of a transpiled language that adds generics definitely
piques my interest. Ultimately, I suppose I would be worried of the language
stalling or falling out of favor, like CoffeeScript.

The name choice doesn't seem that well thought out, which also makes me
question the authors somewhat.

~~~
wowoc
I think the issue with CoffeeScript was that it didn't add anything beyond the
arguably prettier syntax.

Have changes the syntax too, but it is also trying to fix things that often
cause bugs in Go code, it adds generics, and there are a few other features on
the way, too.

------
weberc2
I'm not usually a stickler for syntax, but `interface{}` => `interface: pass`?
It really seems like the indentation approach creates more problems than it
solves. :(

EDIT: Props for writing this in Go though. Oden (the other 'compiles to Go'
language) is implemented in Haskell, which means that I can't hack on it.

~~~
wowoc
That's what I'm a bit afraid of - that it will feel awkward to people without
prior Python experience. I have spent a considerable amount of time developing
in Python, so the way empty interface is written looks natural to me.

~~~
weberc2
I program in Python professionally, and it still feels a bit awkward. :/ I
don't want to make this a bigger deal than it is, but I'm not sure that you
gain much by adhering to the Python syntax. That's just my $0.02. I'm excited
to play around with it though. :)

------
gravypod
Might be worth using just for generics. Template out small bits you need,
compile them to go and use them as libraries for generic-heavy tasks like
sorts and what not.

------
Merovius
So, let me phrase my criticism as questions :)

How do you declare methods on non-struct types? Or are you disallowing
defining your own non-struct types? It seems to me that the method-syntax you
introduced will either be a step back, because it disallows non-struct types,
or it will be a step back because it makes method declaration inconsistent.

How are the generics implemented? The general tone seems to suggest that you
do naive template expansion, but the section about when makes it seem that you
are using interface{} and type-assertions in the generated code.

How is the overloading of make handled (assuming it's actually just
implemented with the existing generic mechanisms)? It can take between 1 and 3
arguments and does vastly different things to them depending on the type
parameter. The latter part might be handled by your specialization mechanism
(with considerable runtime overhead for a very central part of the language),
but the former is not described.

Overall, I admire implementing a language as a hobby project (I always wanted
to do that myself). But I don't see anything that would compel a significant
share of people to migrate over either from python or from go. It doesn't come
close to python's expressiveness and it also lacks go's simple and orthogonal
design.

It seems to me, that you added a few things that are better addressed (and
will be addressed) in an eventual go2 and then more or less arbitrarily
changed a bunch of things for personal taste. The result feels a bit
patchworky; your generics have even more overlap with interfaces than people
have feared about a go addition (which is one of the major reasons it doesn't
have them) due to the type-switchy-when and the syntax changes create a bunch
of inconsistencies.

Still. Plow forwards :) There can only come good of more stuff in the world :)

~~~
wowoc
> How do you declare methods on non-struct types? Or are you disallowing
> defining your own non-struct types?

It will be allowed, through type opening (which isn't implemented yet). It's
mentioned in the intro, I called it "structure opening" but actually it will
work on any non-builtin named type.

I'm not sure how the syntax will look like yet, but say that you have a
struct:

    
    
      struct A:
        func MethodA():
          pass
    

Then you will be able to open it and add new methods to it, it could look like
this:

    
    
      open A:
        func MethodB():
          pass
    

> How are the generics implemented? The general tone seems to suggest that you
> do naive template expansion, but the section about when makes it seem that
> you are using interface{} and type-assertions in the generated code.

No, it's closer to template expansion, "when" is "executed" (for lack of a
better word) during compilation. Inactive "when" branches are ignored by the
code generator (and type checker, thus they can contain code that's invalid
for given instantiation). There's no type-switch in the resulting Go code.

> How is the overloading of make handled (assuming it's actually just
> implemented with the existing generic mechanisms)?

Right now it's not handled at all. I don't want to add default argument values
to the language, so, unless I come up with something better, I'm afraid that
there will need to be more than one "make" function, each named differently.

Thanks for your feedback! I'm well aware that the chances of Have becoming
popular are tiny, but I'm having lots of fun working on it anyway.

~~~
cbHXBY1D
> No, it's closer to template expansion, "when" is "executed" (for lack of a
> better word) during compilation. Inactive "when" branches are ignored by the
> code generator (and type checker, thus they can contain code that's invalid
> for given instantiation). There's no type-switch in the resulting Go code.

I'm not sure I understand. Could you point to where you do this on Github?

~~~
wowoc
Sure, the AST node for "when" is here:
[https://github.com/vrok/have/blob/master/have/ast.go#L159](https://github.com/vrok/have/blob/master/have/ast.go#L159)

Type checker checks the condition before every branch in "when" statements,
and sets the "True" flag if it evaluated to true.

Then the code generator just skips over branches that don't have the "True"
flag set:
[https://github.com/vrok/have/blob/master/have/generator.go#L...](https://github.com/vrok/have/blob/master/have/generator.go#L728)

------
diggan
Interesting! But I would love a clojure-like (or even clojure) that compiles
into go-code and then built into native code (or another solution). I don't
really want to ship .jar files, and I love golang for building CLIs but I
really want to get away from that kind of syntax.

------
gagege
Should have called it Hare, to go along with the rodent theme.

~~~
wowoc
Actually, that's why hare is the mascot. :)

------
leshow
The author claims one of the goals is to write zero cost data structures. i
don't see how thats possible if it compiles to Go, as most data structures in
go have implicit cost associated with it because there is a language runtime
and GC.

Unless he means zero-cost ON TOP of Go, which is an odd definition.

------
NateDad
reposted from r/golang:

> _Have is an indentation based language_

Nooope.

That kills half the benefit of gofmt - fixing indentation.

    
    
      if foo:
      bar()
    

Did I forget a "pass" or did I forget to indent bar? You can't tell, so you
just have to punt.

It also prevents fixing up copy and paste:

    
    
      if foo:
      --paste start--
              if tooMuchIndentation():
                  something()
      --paste end--
          previouslyInsideIf()
    

What would your formatter do here? Did I mean for the last line to be inside
the new if, or outside of it? You can't tell, so you have to make an
assumption, and it'll be wrong half the time.

And that's not to mention all the other benefits of braces, like easy visual
indication where blocks start and stop, having anonymous blocks (without if
true), etc.

Also, requiring methods to be placed inside of structs (or, presumably other
named types like type foo int) means that for large files, it won't be
immediately clear what type a method is for.

Halfway down the 1000 line file network.go you have

    
    
      func *String() string: return self.Name()
    

What type is this declared on? There's no way to know without scrolling up to
the beginning of the type declaration. Also it means that almost all your code
is uselessly indented once for no reason.

~~~
wowoc
Well, that's a more general problem with indentation based languages, but
Python users seem to be happy. It's a tradeoff, code that's (arguably) more
pleasant to read, for a bit more work while writing it.

It's true that gofmt-like tool would be less beneficial, but I think that most
of the things you've mentioned could be helped with editor/IDE support, e.g.
indent-aware paste, block navigation and so on.

~~~
nilliams
Yep this, basically the things gpp mentioned just aren't problems day-to-day
for Python developers.

And the 'halfway down the 1000 line file' one was just plain silly.

~~~
NateDad
Why is it silly?

~~~
nilliams
Straw man basically. Developers shouldn't ever be working with 1000 line
files, except as build artefacts.

------
knocte
Generics and tabs, awesome!

Now, if you remove the horrible feature of ignoring errors by default, I will
play with it :)

------
drcongo
If this manages to bring the readability of Python to Go then I'm all for it.
Good luck!

------
anentropic
"Tabs are preferred"

Aaaarggghh!!!

:)

~~~
Stratoscope
Tabs make great sense in an indentation-based language. One tab, one indent
level. Left and right cursor keys move one indent. No questions of how many
spaces to use, and no off-by-one errors in your spacing.

The only real advantage of indenting with spaces is if you use a column
aligned coding style like this:

    
    
      SomeFunctionName(firstArgument,
                       secondArgument,
                       AnotherFunctionHere(itsArgument,
                                           itsOtherArgument),
                       lastArgument);
    

If you use tabs for indentation, you're into the old problem of "should I use
tabs to indent and spaces to align?"

But this kind of column alignment has many disadvantages: excessive line
lengths, spurious diffs in your source control when you change the length of a
name and have to realign everything, and the fact that you'll very likely
forget to realign something when you do a global replace.

I've seen each of these problems in the Servo source code which uses mandatory
column alignment (examples in one of the links below).

An alternative way to format code is to use indentation only with no column
alignment:

    
    
      SomeFunctionName(
          firstArgument,
          secondArgument,
          AnotherFunctionHere(
              itsArgument,
              itsOtherArgument
          ),
          lastArgument
      );
    

This solves all of the problems mentioned above, and it means that tabs become
a perfectly reasonable way to indent the code, since there's no question of
indentation vs. alignment.

Here are a couple of previous comments with more examples and discussion of
the advantages and disadvantages of indentation vs. column alignment:

[https://news.ycombinator.com/item?id=10206860](https://news.ycombinator.com/item?id=10206860)

[https://news.ycombinator.com/item?id=9469713](https://news.ycombinator.com/item?id=9469713)

~~~
nilliams
Couldn't agree more, this is one thing that Python/PEP8 got completely wrong.
(Leading) column-aligned code falls down more-often-than-not in practice and
is a terrible reason to sacrifice tabs. Tabs are superior. [0]

[0] [http://lea.verou.me/2012/01/why-tabs-are-clearly-
superior/](http://lea.verou.me/2012/01/why-tabs-are-clearly-superior/)

------
sdegutis
The real link:
[http://havelang.org/post/for_gophers/](http://havelang.org/post/for_gophers/)

So it's just Go with Python syntax: _" Have syntax is inspired by Go and
Python, but semantics is usually the same as in Go."_

~~~
wowoc
Not quite. It has extra things too, like generics. But things that exist in Go
are there too, mostly unchanged.

~~~
jerf
First, generic disclaimer: To the extent that you just want to have fun and
learn things, please be my guest. The rest of this post is suggestions from
the point of view of whether you might want others to adopt it in the future.

That "mostly" in "mostly unchanged" is a problem. Have should probably be
either significantly radically different from Go, so that when I use it I'm
not confused, or it should be as similar to Go as possible except that it adds
some features, so that it seems like a nice add on.

Rewriting syntax that ends up really just being a gloss on the existing syntax
(i.e., not really allowing much new expressiveness) is just a hurdle to the
language; it's a hurdle to your implementation, a hurdle to anyone picking it
up and using it, and a long-term burden of trying to explain the _slight_
differences to everybody. See, for instance, the Python 2 vs. Python 3 pain.

Since it seems to me the major feature of Have is giving Go generics, I
suggest comparing with some other things already out there:
[https://github.com/sasha-s/go-inline](https://github.com/sasha-s/go-inline) ,
and I also reference the projects mentioned in the FAQ. I am not saying these
things solve the problem, but you may want to compare notes and steal (in the
"good artists borrow, great artists steal" sense) the good things if you can.
You might also find it helpful to contact the authors or users of those
projects and ask about pain points.

~~~
witty_username
The differences between Python 2 and 3 are not just syntax.

Fixing syntax is easy; 2to3 can do that.

~~~
jerf
Considered from the point of view of the entire language landscape, the point
is that they were minor little changes. Python 3 is not anything like the way
Perl 6 should never have been named "Perl" at all... it's the same language
with some minor fixes that did not bring benefits anywhere near commensurate
with the costs.

(It was one of the great learning experiences of my software career, because I
was full-throatedly in favor of Python 3 back when it was proposed. My support
counted for nothing, so I'm not "responsible" for it in any way, but I still
was _very_ wrong.)

~~~
witty_username
If they were minor changes then 2to3 should work perfectly.

But it doesn't; for example 2to3 can't always fix the shift to Unicode by
default.

