top | item 19086712

About V, the language Volt is written in

570 points| AndyKelley | 7 years ago |volt.ws | reply

342 comments

order
[+] amedvednikov|7 years ago|reply
Hi,

Developer here. I was going to post this here in a couple of weeks after launching the product and creating a separate site for the language with much better information about it.

I'd also like to hear your opinion about not allowing to modify function arguments except for receivers. This is an idea I got that isn't really implemented in any language I know of.

For example: mut a := [1, 2, 3]

So instead of multiply_by_2(&a)

we have to return a new array (and this will later be optimized by the compiler of course)

a = multiply_by_2(a)

I think this will make programming in this language much safer, and the code will be easier to understand, since you can always be sure that values you pass can never be modified.

For some reason all new languages like Go, Rust, Nim, Swift use a lot of mutable args in their stdlibs.

You can still have methods that modify fields, this is not a pure functional language, because it has to be compatible with C/C++:

fn (f mut Foo) inc() { f.bar++ }

[+] physguy1123|7 years ago|reply
I'm not sure if I'm the target audience for this (low-latency trading), but here's my thought - code which would allocate in a fast path is a strict no-go for me, and this runs fairly close to that in a few regards:

> It seems easy to accidentally make allocating code allocate by changing some variable names (b = fnc(a) - oops, allocation)

> I would be extremely wary of trusting a compiler to realize what sort of allocations are optimizable and not - I already have problems with inlining decisions, poor code layout, etc in fairly optimized c++/rust code compiled by gcc+llvm.

Replace allocation with any other expensive work that duplicating a datastructure would result in, and you have the same story. I suspect many of the people that would be evaluating this compared to C/C++/Rust have similar performance concerns.

[+] nicoburns|7 years ago|reply
I think Rust and Swift's approach of approach of making the user explicitly annotate (both at function definition time and a call time) these kind of parameters works pretty well.

I think you're right that it can often be an antipattern. But there are also use cases (usually for performance reasons), and the real problem occurs when you are not expecting the modification to happen. If the parameter is annotated then it's obvious that it might be mutated, and less of an issue...

P.S. Looking forward to the open source release. This langiage looks pretty nice/interesting to me, but there's no way I would invest time into learning a closed source lanaguage.

[+] henrikeh|7 years ago|reply
In Ada, procedure and function arguments must be annotated with whether they are “in”, “out”, “in out”. “In” can never be modified, “out” has no initial value and “in out” has both initial value and can be modified.

Overall if you don’t know Ada I’d recommend that you take a look at the features of it. It has very similar design goals as your V.

[+] Straw|7 years ago|reply
Although you can certainly go the pure functions route, I wouldn't recommend it for performance.

There's a false dichotomy between functions and methods, which are simply (sometimes dynamically dispatched) functions with a special first argument. If you allow mutable first arguments, why not any argument?

Instead of the language deciding what's mutable and not, I'd rather have a const system like C/C++ to ensure that changes aren't happening behind the programmer's back.

[+] coldtea|7 years ago|reply
Hello, this is an excellent language! Have been looking for something like this for a long time!

Re: "not allowing to modify function arguments except for receivers" -- maybe instead all fields const by default, but having something like an optional mut modifier?

A quick question, how does hot reloading work (with presumably AOT compilation and no runtime)?

(Perhaps there's a OS mechanism to change already loaded code in memory that I should know).

[+] masklinn|7 years ago|reply
> For some reason all new languages like Go, Rust, Nim, Swift use a lot of mutable args in their stdlibs.

Both Rust and Swift require specifically opting into parameter mutation (respectively `&mut`[0] and `inout`) and the caller needs to be aware (by specifically passing in a mutable reference or a reference, respectively), only the receiver is "implicitly" mutable, and even then it needs to be mutably bound (`let mut` and `var` respectively).

Inner mutability notwithstanding, neither will allow mutating a parameter without the caller being specifically aware of that possibility.

The ability to mutate parameter is useful if not outright essential, especially lower down the stack where you really want to know what actually happens. Haskell can get away with complete userland immutability implicitly optimised to mutations (where that's not observable), Rust not so much.

[0] or `mut` in pass-by-value but the caller doesn't care about that: either it doesn't have access to the value anymore, or it has its own copy

[+] fooker|7 years ago|reply
> (and this will later be optimized by the compiler of course)

Do not underestimate this part. It can take a surprising amount of effort to get these things right and performant.

[+] register|7 years ago|reply
This is exactly what I was looking for. There's no real option for a language that allows interactive coding and it's easily embeddable. Please open source asap. You will get contributors starting with me.
[+] akrymski|7 years ago|reply
I actually think having different models (functional and imperative) just adds to confusion. I don't think immutability is all that useful personally, unless the language is purely functional to begin with. I'd keep it simple and stick to C as much as possible.

Why not go the other way and pass everything as a reference? After all that's what Java does, and that's how you'd pass any struct in C anyway. It's a rare case when I need to forbid the calling function to not modify an argument for whatever reason or because I don't trust it - in that case you can make a copy beforehand or use a const modifier. But in most cases I'd expect functions to modify the memory that I pass in, instead of allocating and returning new structures.

Why not have a simple `class` construct as in JavaScript? Keeping functions together in a class is very convenient and means you don't have to pass the struct as the first argument each time. That way `Array` can be a class, and would always be passed by reference. No ambiguity there, class instances are always mutable. Everyone is already familiar with it, it works.

A class method can simply map to a global C function: ``` ClassName_MethodName(*self, ...) ```

As an aside, using a syntax that people are already familiar with (and APIs!) would be great, and make something like this instantly usable. JavaScript has a fairly small core API which would be easy to emulate for example.

[+] boomlinde|7 years ago|reply
I'm thinking that it's easy to make a mistake that would prevent the optimization from happening, so I'd personally much rather be explicit about mutability than betting on having satisfied the optimizer.

This looks like a really interesting project, and I look forward to trying it out!

[+] js2|7 years ago|reply
I have a possibly unhealthy obsession with using namedtuples in my Python and so this pattern appears frequently in my code:

    object = object._replace(foo=1)
But I usually encapsulate the _replace call in the class so it's more like:

    object = object.update_foo(1)
I personally find it can make the code easier to understand, like you say, but it seems like you're getting a lot of disagreement from the other comments.
[+] rurban|7 years ago|reply
pass by copy is a traditional safe mechanism in functional languages, esp. for multithreading. It can also be made fast enough.
[+] friday99|7 years ago|reply
What about the case of multiple outputs? It's traditional to have functions that take other mutable arguments to store different auxiliary return values in. So, with this proposal, you couldn't do that and would have to construct random blobs to store all return values and then unpack them.
[+] IshKebab|7 years ago|reply
I think it would be a bit weird if fields of structs can be modified, but bare values can't. Kind of feels like the inconsistency between `Integer` and `int` in Java.

So I would say that having to explicitly mark function parameters as mutable (like in Rust) is a better approach.

[+] jonhohle|7 years ago|reply

    > This is an idea I got that isn't really implemented
    > in any language I know of.
Is this different than an arg declared as a const reference in C++. Or since fields are still mutable, like `final` arguments in Java?
[+] skybrian|7 years ago|reply
If you can't mutate an argument, does that mean you can't call any of the argument's methods that mutate it, either?
[+] robobro|7 years ago|reply
ever studied Limbo? look at Limbo instead of Go.
[+] calebwin|7 years ago|reply
Isn't the main reason why languages like Go and Rust don't do that because it would produce a ton of memory garbage?
[+] lucas_membrane|7 years ago|reply
Ada does not allow functions that alter parameters for their callers (out mode parameters).
[+] whalesalad|7 years ago|reply
Yes. Don’t mutate in place :thumbsup:
[+] milancurcic|7 years ago|reply
Pure functions in Fortran do this.
[+] pcwalton|7 years ago|reply
> V is compiled directly to x86_64 machine code (ARM support is coming later) with no overhead, so the performance is on par with C.

Direct compilation to x86-64 machine code does not get you performance on par with C (by which I assume the author means GCC or Clang). The optimization pipelines of GCC and Clang have had decades of work put into them by some of the best compiler engineers in the world.

Since the author states that the compilation time is linear, this would seem to imply that a full suite of optimizations are not being done, since many optimizations done by GCC and Clang have nonlinear complexity. It is easy to get fast compilation if you don't perform optimizations.

> - Thread safety and guaranteed absence of data races. You no longer have to constantly ask yourself: "Is this thread safe?" Everything is! No perfomance costs either. For example, if you are using a hash map in a concurrent function, a thread safe hash map is used automatically. Otherwise a faster single thread hash map is used.

This description doesn't guarantee freedom from data races. (Java's memory model basically fits this description, for instance, except for the specific case of hash tables, which aren't built into the language.) Even if it did, the tricky part is determining what a "concurrent function" is. The obvious ways one might imagine doing this tend to fall down in the face of higher-order functions.

[+] amedvednikov|7 years ago|reply
Yes, you are right. I had a mental note to update the description, I never expected this to be posted on HN so early :)

Just updated it:

> V is compiled directly to x86_64 machine code (ARM support is coming later). There's also an option to generate C code to support more platforms and achieve better performance by using sophisticated GCC/clang optimization.

[+] SiVal|7 years ago|reply
My two biggest questions about V are 1) How is memory managed?, and 2) How is concurrency done?

"V has no runtime". No GC, but you don't have to manually release memory, like Rust but much easier. Sounds great. How?

And "no race conditions ever" and "everything is thread safe". You can do that with "no runtime" fairly easily if there's no goroutine-style concurrency. I didn't see any mentioned, but I could have easily missed it.

Those two aspects of the language are fundamental enough that I would certainly want to read about them near the top of any overview of the language.

[+] dang|7 years ago|reply
Making a programming language specifically for the needs of one program, then developing that language and the program together, is an underestimated strategy. I believe the world would be more interesting if more people applied it—because then we'd get more qualitatively different new systems. The Sapir-Whorf hypothesis may not be something people currently believe about natural language but for sure it's true about programming: the language you program in conditions what you think, which conditions what program you write. When the two evolve together, evolution can go to new places.

This strategy is time-honored in the Lisp world, where making a language and writing a program are more intertwined, and the cost of making a language much lower, than they usually are.

[+] mathgladiator|7 years ago|reply
Awesome, I love to see new programming languages in action. This is great. Some thoughts.

First, ignore negativity and focus on getting constructive feedback. One of my tiny regrets is that I abandoned one of my projects due partially to negative energy. Many years ago, one of my projects was shared here ( https://news.ycombinator.com/item?id=226480 ), and the feedback was kind of a buzzkill (especially since I wasn't the one sharing it).

Second, think about the growth you want. While I could ignore the buzzkill and keep the faith, I used my language to put a real product out into the world. The crazy thing is that I got it working and working very well, but when it came to hire. It was a cluster fuck. I should have spent a bunch more time on documentation and examples, but I had other concerns that were higher priority. I ultimately had to abandon the whole thing, and I just rewrote everything in C# and used Mono. It was painful, but the company was able to grow faster since the tools were somewhat standard and a plethora examples for the new hires.

When I look back, I was onto something. If I had kept the faith and pushed through, then I would have created something very similar to HHVM which Facebook uses. My strategy back then was to create a less awful language, improve it, then port the platform bits to a better ecosystem and preserve the "business logic".

My core advice with the programming language side of the house is to find a partner for you to lead/follow with shared values. Make it open source as soon as possible, don't wait.

[+] didip|7 years ago|reply
Wow, I like the selling points:

* Strong modular system and built in testing.

* Global state is not allowed.

* There's no null and everything is automatically initialized to empty values. No more null reference crashes.

* Variables are immutable by default and functions are partially pure: function arguments are always immutable, only method's receiver can be changed.

* Thread safety and guaranteed absence of data races. You no longer have to constantly ask yourself: "Is this thread safe?" Everything is! No perfomance costs either. For example, if you are using a hash map in a concurrent function, a thread safe hash map is used automatically. Otherwise a faster single thread hash map is used.

* Strict automatic code formatting. It goes further than gofmt and even has a set of rules for empty lines to ensure truly one coding style.

Especially eye catching is the 2 mode of every data structure. Switch to thread-safe if there are concurrent access.

[+] anderskaseorg|7 years ago|reply
“No variable shadowing” might sound great when you’re thinking about that one time someone confused you for three seconds with the addition of a new inner variable with the same name as an outer variable. But once you realize that it equally means forbidding the addition of a new outer variable with the same name as an inner variable (even though those inner variables are supposed to be implementation details)—and, as a corollary, you can never add new builtins to the language without breaking backwards compatibility—you’ll realize that most languages allow shadowing for a reason.
[+] coldtea|7 years ago|reply
Is this a real language, or am I dreaming this?

Those are exactly the ideas I had for what would make a perfect language! (Assuming they're implemented properly of course).

Simple features. Immutable and pure by default (but not dogmatically so). Fast compile. Hot reload. Automatic C interop. Fast-ish. Built in niceties like hashmaps, strings, and vectors (niceties compared to bare C). Receivers so you don't have to do the song and dance you do in C to tie structs and functions. No header files!

Go came close, but no cigar. Rust added the whole kitchen sink and loads of accidental complexity. Anxious to see how this fares...

[+] johnt15|7 years ago|reply
It's interesting that the roadmap of volt has been saying v1.0 is just around the corner for the past half year. The other roadmap items also don't change much.

https://web.archive.org/web/20180615121501/https://volt.ws/

https://web.archive.org/web/20181023093131/https://volt.ws/

It would be great if the roadmap contained realistic items. Once a user is burned by an unmet expectation he won't believe anything else on the website.

[+] amedvednikov|7 years ago|reply
Yes, I've done a terrible job with estimations and for 9 months I lived in "release tomorrow" mode.

I made lots of mistakes that caused the delay, I'll post a detailed blog about it.

Should have sticked to "it's ready when it's ready".

Ironically this time it it really is going to be released tomorrow (Feb 7).

[+] slaymaker1907|7 years ago|reply
I think doing away with global variables is not a very good idea. While using globals is usually a bad idea, there are many instances where globals are appropriate (at least for languages supporting mutability). People who say they never use globals usually do use globals and are just trying to convince themselves they are not because they heard they were bad from somebody.

The entire Spring framework is IMO an elaborate construction built so that engineers could use global variables without their managers finding out. There is little to no difference between carefully using global variables and Spring dependency injection except syntax.

The best solution I have ever seen to global variables is definitely parameterize with Racket (https://docs.racket-lang.org/guide/parameterize.html). I don't think Racket was the first language to come up with this, but it was the first one I am aware of. The basic idea is that you define some global with a default value. However, you can call parameterize to change the value for the duration of some input function. It is made thread safe by using thread local memory. It then resets the parameter back to the default value at the end of the function.

On the other end of the spectrum, I think Rust also has a very good implementation of globals. It will let you use global variables, but you have to declare it as mutable, use some form of locking, or use an UnsafeCell. Additionally, you have to mark your code as unsafe any time you try to read or change this global variable.

[+] edgarvaldes|7 years ago|reply
I like to know that there are still developers for whom the size of an application is an important issue.
[+] cschep|7 years ago|reply
100+ MB down to 5 MB is such a nice win, it's amazing that the author even bothered to continue from 5 MB down to 100 KB. Very impressive!
[+] rafaelvasco|7 years ago|reply
Sounds too good to be true. If this is released it'll be serious competition to Rust, Nim, Zig, etc. Lets hope for the best. There's just so many amazing features. There's even a graphics library in it.
[+] ilovecaching|7 years ago|reply
To the problem you were originally trying to solve, why not just use Rust? Go and C are really about as related as Java and C. Rust would have met all your requirements, and has a lot of features you added to V to begin with.
[+] amedvednikov|7 years ago|reply
Slow compilation. Complexity.
[+] avisaven|7 years ago|reply
I had been looking for this exact project, but I couldn't remember its name for the longest time. But I remember that home page exactly. Doing a bit of seraching it turns out volt.ws appears to be a rebranding of a previously posted [1] Eul (eul.im), posted by alex-e (whom I assume is its author). Either way, volt.ws and the associated V language sound quite interesting, I look forward to hearing more about this in the future.

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

[+] DaiHafVaho|7 years ago|reply
As an (anonymous) programming language designer, a few bits of feedback.

First, nice concept, but without open code, it might as well not exist, and without open specification, it might as well be yours alone, like one of Tolkien's languages. Closed languages wither and die, and yours seems well onto that path.

Second, what makes V compelling to you appears to be completely uninteresting to me in terms of language design. It might as well compile from V to Go; I can't see why not!

Whenever a language designer appeals to simplicity, they are usually appealing to whatever makes it possible for them to be productive, and they are usually missing that the productivity is personal because the designer is the one who builds the language. The GL demo seems to be a great example of this sort of situation.

I hope that you publish your work so that we may properly critique it.

Edit: Here is another language designer who is not me saying "closed languages die" (https://blog.golang.org/open-source). I think that, until we actually have a compiler for V (or whatever it is hopefully renamed to before release) in our hands, we ought to be extremely careful about trusting that any of this exists. It is all too common in PLT/PLD for somebody to come in with bold claims, outrageous mockups, and zero toolchain. I addressed what I saw, which is yet another compiles-to-Go hobby language. To become more than that requires a committed community and a common repository of open code, and the author appears to have only the former.

[+] ww520|7 years ago|reply
> Closed languages wither and die, and yours seems well onto that path.

This is unnecessary harsh. The author has already said it will be open sourced later. I can understand the reasons to not open source now. Managing an open source project is no small work.

Second, notwithstanding V's slim feature set, it's already more successful than 99% of language design attempts out there in that it ships. It certainly succeeds in letting the author to build his other projects faster and easier. It fulfills the author's own needs. I'm sure Perl and Python started that way.

[+] asdfasgasdgasdg|7 years ago|reply
> I hope that you publish your work so that we may properly critique it.

I don't know about this author, but for me, this would emphatically not be a motivating reason to publish my work. I might publish work so that someone could get some use out of it, or to show off my brilliance. But if all you're going to do is critique it (no doubt with all the familiarity born of five minutes of looking at the tutorial), then I'd just as soon you never see it.

>Here is another language designer who is not me saying "closed languages die" (https://blog.golang.org/open-source).

I don't think the person you're quoting would advocate that languages must start out as open source. Go sure didn't. It was developed closed source within Google for two years before it was even announced.

[+] wilg|7 years ago|reply
It's not necessary for it to be a general purpose programming language, though. I think it is kind of neat to have a very specific, personal language that fits your mental model. On a larger team, probably not what you want, but there are other languages that are optimized for that.

Basically you're right if the creator wants a widely-adopted general-purpose language. But there's other valid approaches I think.

[+] dom96|7 years ago|reply
> It is all too common in PLT/PLD for somebody to come in with bold claims, outrageous mockups, and zero toolchain

This. It's crazy to me how quickly developers are ready to get behind something without even being able to use it. Jai is similar in this regard.

It's easy to make wild claims like "super fast compilation" or "can be translated from C++" when you don't have hundreds of users, all finding edge cases and wanting different things. Especially easy when you haven't released anything so everybody is projecting their favourite features onto the language.

[+] amedvednikov|7 years ago|reply
Like it says on the website, the language will be open-sourced later in 2019.
[+] hexmiles|7 years ago|reply
For me personaly the killer fature is: C/C++ to V translator

Having all my library in the same language make a lot thing like debugging and testing easier. It also semplify the mental model i have of the program.

Also C(lang) interop is my main struggle with go. For me it is such a pain that something i wrap a c library in a stdout/stdin server and just spawn it and use cap'n'proto for communication. When you use cgo you lose the easy cross-compiling, i would love for something similar in go and/or rust.

I wonder if llvm could be used to implement a sort of universal transpiler. even if it not use the target language in a semantic language it still make a lot of thing easier.

[+] stabbles|7 years ago|reply
I tried the app on the mac and it's very buggy.

I couldn't save settings, and from then it kept on crashing after restarting the app.

[+] gbersac|7 years ago|reply
I was considering downloading it, but I think I won't now that I read your answer. Do you know of any good competitor ?