Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: Vivaldi programming language (github.com/jeorgun)
52 points by jeorgun on Feb 15, 2015 | hide | past | favorite | 25 comments


So this[1] post recently made its way across the HN front page, which I found serendipitous given my current side project. There's nothing terribly groundbreaking in my language— everything in it is basically taken from Ruby, Scheme, or Python— but I certainly learned a lot making it, and maybe some of y'all will find something of interest in it.

[1] https://news.ycombinator.com/item?id=9040029


Nice work! What was the motivation for creating the vivaldi language?


Hey! Creator of Wake here.

This looks like a nice language! Lots of syntactic niceties, and it looks extremely feature complete.

Nice work! I'm not surprised you learned a lot given how many features it supports!


why mutable strings, why ?


Got any recommendations for resources to get started creating one's own language?


Pat Shaughnessy's Ruby Under a Microscope[1] is a fantastic resource for looking at Ruby's internals, especially concerning parsing, Ruby's class structure, and the YARV virtual machine.

It's probably easiest to begin with a Lisp dialect, since a basic one needs only two data types (singly-linked lists and symbols) and its eval function is so simple. Peter Norvig has a great tutorial[2] on implementing a Lisp in Python.

Beyond that, it can be helpful to look at the source code for other languages similar to what you're looking to create, to get a sense of how they do things.

That's more or less what I found helpful, in any case. Good luck!

[1] http://patshaughnessy.net/ruby-under-a-microscope [2] http://norvig.com/lispy.html


For the parsing aspects, reading about parser generators or the like would be super useful


I would not recommend using a parser generator tool to build a recognizer por any programming language,unless you design your language to be LL(1) or LL(k) witk a low value of k. Otherwise you are going to suffer a lot with parsing issues.

Parser generators usually have a very limited number of target languages, so you might find yourself stuck into a language you do not want to code in.


hmm, your results may vary (whitespace-sensitive languages, but that's tricky in pretty much any toolkit), but in my experience most DSLs that people want to write fit well within LL(k). Java works in it, after all.

I started out with Yacc, though, and that helped me out a lot more...


> Interpreted language inspired by Python, Ruby, Lisp, and so forth

For a few seconds I wasn’t sure if this was a pun with a reference to the Forth programming language, but it’s not.


There is another project called Vivaldi, a new web browser. It's been featured on HN a few times.

https://vivaldi.com/


Dang it! I googled and everything. No slight against them intended; it looks like a really cool browser, and certainly more of a Real Project than my little language! Hopefully the domains are different enough that the overlap isn't too egregious, but if not there are plenty of other Baroque composers I could switch to.


Well, Apple stole 'Swift' from a different language (was quickly changed to "parallel scripting language"):

http://en.wikipedia.org/wiki/Swift_(parallel_scripting_langu...

He created something in an entirely different category. Both projects have similar chances to succeed. What is the problem?


People just like sharing that kind of thing. When I made this little page http://chrisdone.com/z because I couldn't be bothered thinking of a better name, there were dozens of people commenting and emailing me expressing concern that there is already a Z programming language and I should respect other authors etc.


> What is the problem?

Nobody said anything about it being a some sort of a problem.

Actually, the reason why I checked this link and the comments section is because I thought that this is in some way related to the Vivaldi browser. After reading the comments, I realized that I was completely wrong.


I really wish Ruby had some kind of `var` or `let` syntax so it was a bit easier to determine when one was calling the method "foo=" or when one was assigning the local var "foo" to something. Having this would reduce the amount of `self`s in the code for class definitions.


Oh, that is evil.


Looks like a fairly well put together language.

A few things that were not explained in the README:

Why did you decide to create your own programming language?

> every type in Vivaldi inherits from Object (which in turn inherits from... itself)

What was the reason behind making Object inherit from itself?

What is the largest program currently written in Vivaldi?

edit: It looks like the first commit on github is 22 days ago, did you make the whole language in 22 days?


1. Mainly for fun! Languages are pretty complex, so I got to learn about number of things (e.g. recursive-descent parsing, closures, Ruby and Python internals) in making it, and it's pretty rewarding watching programs run successfully.

2. Mainly that, because of the way objects are defined in the C++ (in value.h), it had to inherit from some type. I could just fudge it and make it inherit from nil or something, but there isn't any particular downside to the current system, and it has the added benefit of ensuring that obj.type().parent() is always successful.

3. Nothing much beyond a few test scripts (ProjectEuler solutions, etc) at the moment. Since there isn't a C API yet, it's pretty hard to make anything that requires networking, GUIs, etc., so adding that is near the top of my TODO list.

4. I might have started a few days before the initial commit (I can't remember ATM), but more or less, yeah.


Is there any build/install instructions? Want to play around :)

EDIT:

  git clone git@github.com:jeorgun/Vivaldi.git
  cd Vivaldi
  # if you don't have boost then run 
  brew install boost
  mkdir build
  cd build
  cmake .. && make # cmake version 3 or greater is required


Oh, whoops— sorry about that! I added some instructions based on yours to the README; better?

Also, if you run in to any issues, feel free to let me know; I only have my MBP and an old Thinkpad T60 running Arch Linux to test on, so I could very well have unwittingly done something non-portable (I'm assuming that Windows support is a complete no-op, but I'd be happy to hear I'm wrong).


This looks really cool! Some random feedback. It's your baby, so feel free to ignore any and all of this you don't agree with.

First off, you did two things right that a lot of hobbyists (including myself, multiple times) do wrong right out of the gate:

1. You wrote some nice, readable introductory docs.

2. You didn't make the language syntactically weird for no good reasons. I can instantly read your code samples and understand them. Yay!

---

There's a good chance you'll end up regretting making strings mutable. It means APIs that receive and store a string have to either copy the parameter (slow, easy to forget) or run the risk of having something that they would be unchanging change under them.

This is a problem with mutability in general, but I think strings hit the pain point most strongly since they're immutable in other languages.

---

You have lots of methods that don't take arguments (size(), start(), end(), etc.). Some kind of getter syntax would be nice to lose the pointless "()".

---

I like your range syntax. I'm using ".." and "..." (like Ruby) in a hobby language of mine[1], and it's definitely not intuitive to many users.

[1]: https://github.com/munificent/wren

---

Your mixture of ":" for functions and control flow but "do ... end" for blocks hurts my soul in some hard to define way. There's nothing intrinsically wrong with it, but I see ":" and expect Python-style indentation then see "end" and get all confused.

It might be nice to try to pick one or the other -- use indentation for blocks, or "end" for functions and control flow.

---

I think you may eventually find the way "self" is dynamically bound to be an annoying frustration. What you have is semantically simple and follows JS and Lua.

But it trips people up when people want to do things like store a reference to a method in a callback and invoke it later. When that helps, you'll have forgotten the old "self" reference.

Of course, solving this is also fairly complex. It usually requires some kind of explicit function/method distinction (makes the language more complex) or an explicit way to close over "self" (easy for the user to forget).

---

"All variables must be declared before use:"

Damn straight. Implicitly declaration gives me hives. :)

---

I like your cond statement, though I've never personally dug the name "cond". The semantics are neat, though.

---

You could get rid of "try" and just allow any block to have a catch clause. That's what Ruby does, and I've always found it elegant.


Not at all— any feedback is appreciated :)

I'm beginning to have doubts about String mutability. Fortunately the only actually mutating method at the moment is append, which is redundant with add but for the mutability, so I might just tear that out.

Required parentheses on functions are pretty unfortunate. I'm mainly trying to avoid the situation in Ruby where trying to access functions as first-class objects requires all sorts of weird syntactic overhead. Possibly I could have some kind of prefix operator, so (say) &obj.method would return the function object, and obj.method would call it?

I agree about the ':' 'do/end' ugliness. Originally blocks were delimited by braces, but I think the Ruby-style delimiters look nicer. Frankly I'd prefer to get rid of the ':', but for single-expression functions that looks pretty awful. I could do Haskell-style '=' (Haskell of course being where the 'function-body-is-single-expression' thing came from), but

    fn foo(x) = do
      ...
    end
is also pretty weird-looking; kind of like Scala's function definitions, which I find really abrasive for reasons I can't fully explain.

Binding 'self' is also basically a compromise. Originally it was stored in the method, but that required copying each type's methods (and each parents' methods) into an object on instantiation, which was a pretty much unacceptable performance hit. My thinking is that, whenever you'd want to pass a method 'obj.method', it's equally possible to pass 'fn (x): obj.method(x)'.

I need to rework the 'try...catch' statements in any case; their current semantics are incredibly horrible (it wraps, then immediately calls, the try body in a temporary lambda). Maybe I will just incorporate them into blocks— thanks for the idea!


> Originally it was stored in the method, but that required copying each type's methods (and each parents' methods) into an object on instantiation, which was a pretty much unacceptable performance hit.

I think more a typical solution is to dynamically bind `self` like you do now on normal method calls. But when a reference to a method is stored, you bind `self` to the original receiver at that point in time.

Basically, you treat it like a closure.


This looks like Ruby. Why not just use Ruby?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: