The V Programming Language
vlang.io
vlang.io
"I do not plan to make any future update posts about the V programming language in the future. The V community is something I would really rather not be associated with. This is an edited-down version of the post that was released last week (2020 M06 17).
"As of the time of writing this note to the end of this post and as far as I am aware, I am banned from being able to contribute to the V language in any form. I am therefore forced to consider that the V project will respond to criticism of their language with bans. This subjective view of reality may not be accurate to what others see."
for anyone considering getting involved, read christine's three articles on the topic first: https://christine.website/blog/series/v
Also, would be good to know what are the contributions. I have looked at the github page of V contributers https://github.com/vlang/v/graphs/contributors and have not find Chrinstine there.
Even if they banned you from GitHub, they did not rewrite git history, I hope? I have not found any commits authored by you in the V repository:
git log | grep Author: | egrep -i '(christ|xe)' | sort | uniq
116 Author: Alexey <alex.esprit@gmail.com>
1 Author: Alexey Lustin <allustin@users.noreply.github.com>
1 Author: Bryan Christopher Johnson <bryanchristopherjohnson@gmail.com>
1 Author: Chris <chris@suletuxe.de>
1 Author: XeGrox <52340924+XeGrox@users.noreply.github.com>>Do not shell out to arbitrary commands in the standard library for any reason. If an attacker can somehow run code on a server with a V binary that uses the download_file function, they can replace curl with a malicious binary that is able to do anything the attacker wants.
I don't understand this threat model. If an attacker is in a position to replace /usr/bin/curl with a malicious binary, surely you're already pwned? And surely an attacker could just as easily switch out libcurl.so as the curl binary? I just can't make sense of any threat model which treats the OS as untrusted.
Shelling out also means the process will unexpectedly stop working if /usr/bin/curl disappears (or wasn't installed in the first place), whereas that's a known and expected issue for libcurl.so and there are established tools (eg `ldd /bin/program`) for tracking such dependencies.
Actually, if you have actual destructors, it’s even potentially hazardous. Rust deliberately eschews static constructors and destructors due to their problems, so I presume it would fall foul of this test of yours as well. It offers this explanation: https://doc.rust-lang.org/1.6.0/complement-design-faq.html#t... (link is to the Rust 1.6 docs; in theory by the next release the content was ported to the main site, but I can’t find it and suspect it got lost at some point).
Now if you’re a library, then having the ability to deinitialise your library might be useful. Probably not, but it might be.
It doesn't have to be "a library" -- as soon as you want to test it, you don't want it to fail the trivial tests. Nobody wins anything by keeping that in that state.
Look at this excerpt from the Valgrind manual:
> Since the block is still pointed at, the programmer could, at least in principle, have freed it before program exit. "Still reachable" blocks are very common and arguably not a problem. So, by default, Memcheck won't report such blocks individually.
https://www.valgrind.org/docs/manual/mc-manual.html#mc-manua...
See https://github.com/vlang/v/tree/master/vlib/v/tests/valgrind . The automatic memory management is work in progress right now, but we do have a growing battery of tests for it.
I currently would not use V for a long running program for exactly that reason, unless it is a very simple service and I free everything manually. That said its -autofree mode is improving daily.
I would be surprised if embedding a string literal into a Rust program would cause a runtime dynamic memory allocation. There is no reason for that: it can be embedded into the binary as static constant-initialized data.
So I would presume the opposite: I would expect that the comparable Rust program would not fail this Valgrind test, because it would not perform any dynamic memory allocation at all.
I don't know anything about V, but I would similarly wonder why this program requires malloc().
I decided instead to focus just on the matter of what happens if you do allocate in such a global—which Rust doesn’t let you do directly, you deliberately have to use a trick like lazy_static which constructs on first use and then deliberately leaks so that it never has to destroy.
I did notice then though that the playground was taken down, and there is this: https://web.archive.org/web/20191223200601/https://christine... (unfortunately I could not find an earlier snapshot, sorry)
And requires an OS to run too. That's another dependency! This and memory leak, seems quite forced. Ad homminens doesn't help either.
You're one of the most knowledgeable people I've seen, with a consistently incredible blog I've learned so much from.
At the end of the day, it's an experimental language that (I thought) was fun to mess around with. Not a very kosher way to respond to factual criticism.
The last article had to be edited down because as it was written initially (see the git history of https://github.com/Xe/site) it made the V cult come after me. This among other things is why I do not plan to write about V in the future.
For anyone interested:
https://github.com/Xe/site/pull/167/commits/354c6079acc2d02a...
For example, compiling 1000 files with 1200 printfs results in ~80mb (according to my poor math skills) worth of static strings and then you state they aren't doing a very good job of creating small binaries because, dunno? Sure, some fancy whole program optimizations should be able to figure out the 1.2 million functions are basically the same and just compile one version -- which, honestly, you'd think the C++ compiler could also be able to figure out but seems to not be doing either.
Not that I think they should be banning people for things like this.
--edit--
Actually...thinking about this a bit it seems a particularly hard optimization problem since the functions only vary by the address of the string they print so the optimizer would need to know this detail while determining the function hash (or whatever is used for equality testing).
--edit2--
Yep, saw the downvotes coming...perfectly fine to bash on someone else's hard work on a new language though.
In all actuality, if I were working on an optimizer I don't even think I'd bother with something like this because if you program like this (duplicate functions) in The Real World™ then you get what you deserve.
As a V contributor, I regret that you decided that. Even though I do not like your attitude towards what is in the end an open source project with many contributors, I do think that your posts when they contained objective and reproducible examples, were actually contributing indirectly to make V better, by pointing out our weak sides at the time of writing.
V is essentially a much cleaner version of Go, syntactically. Though it adds many features that turn it into one of the nicest (IMO) languages to write.
It adds:
- Hot reloading, on a compiled language (WOW)
- Pattern matching/match statements
- Option/Sum types
- A really clean approach to handling Maybe results that I haven't seen in other languages before -- EDIT: I take it back, apparently my own ignorance here
- Generics
- C interop and compile/build integration that's incredibly easy
Some of my favorite bits: // Error-catch + propagation on Maybe's with "?"
fn f(url string) ?string {
resp := http.get(url) ?
return resp.text
}
// Identical to this -- Option types must be handled with "or" if not "?"
resp := http.get(url) or {
return error(err)
}
return resp.text
number := 2
s := match number {
1 { 'one' }
2 { 'two' }
else { 'many'}
}
Additionally, the devs/community on Discord are really friendly, and they spent an hour helping me compile Facebook's reference C++ GraphQL parser library, and interop with the C API from V. I'd never touched low-level stuff before and the experience was a blast.This was all it took (minus figuring out the C++ build process):
// app.v
#flag -I libgraphqlparser_compiled
#flag -L /home/user/Projects/vlang-graphql/libgraphqlparser_compiled
#flag -l graphqlparser
#include <GraphQLParser.h>
#include <GraphQLAstToJSON.h>
struct C.GraphQLAstNode{}
fn C.graphql_parse_string(text charptr, error &charptr) &C.GraphQLAstNode
fn C.graphql_ast_to_json(node &C.GraphQLAstNode) byteptr
node := C.graphql_parse_string("query MyQuery { id email }", "Failed to decode")
json_str := cstring_to_vstring(C.graphql_ast_to_json(node))
println(json_str)
And because the primary compilation target atm is C, performance is generally screaming fast.---
Edit: Want to clarify it's still experimental. As a concept/language, I found it fun.
See Christine Dodrill's negative experience and valid criticisms below for the other side of this coin.
It is very useful for tweaking code, but if you make more substantial changes to your state, currently hot code reload will not help you, and you may be better of just restarting your app.
Various systems solve that in various ways, but it's definitely complex and difficult.
Rust has exactly the same question mark syntax, and obviously V copied it from Rust.
Copying good ideas from other languages is right.
> I haven't seen in other languages before
But you did not know that the syntax was derived from Rust. And the value of a review of some programming language from a person without basic knowledge of the space is not very helpful.
It's likely that you missed a lot of other important details. Like this one:
> V is essentially a much cleaner version of Go, syntactically
Syntactically only, yes. But it is very different from Go, because it does not do garbage collection.
Sorry.
match maybe_error {
Ok/Some(val) =>
None/Err =>
}result.or_else(|err| ... )
Or
result.map(|value| ... )
1. Option/Result are unified into a single type, ?T.
2. It is not parameterized over the error type.
3. The Ok() case does not need to be marked (ex. you write 1, not Ok(1)).
4. In addition to the x? sugar, there is also x or { ... } sugar, which is like Rust's x.unwrap_or(|err| ...) except without the closure so you can eg. break or return from the block. There is also if y := x { .. } else { ... }, which is like Rust's match x { Ok(y) => ..., Err(err) => ... }.
These are all reasons you could think V has cleaner Maybe handling than other languages.
This is not a positive. Option<T> and Result<T, E> have semantically different meanings. This is like saying integers and strings have been unified into a single type: string.
https://news.ycombinator.com/item?id=19403271 (191 points / Mar 15, 2019 / 182 comments)
https://news.ycombinator.com/item?id=19526924 (61 points / Mar 30, 2019 / 101 comments)
https://news.ycombinator.com/item?id=20229632 (146 points/ June 20, 2019 / 137 comments)
A quick lookup on star ranking gives surprising results for V: * Go 76.5k * Rust 48.2k * V 18.5k (??) * Crystal 15.2k * Nim 9.9k * Zig 6.6k
Peak tribalism. Unfortunate coming from us developers, a segment that often prides of being detached from emotion.
Well I've got to give it to V for rolling without LLVM and forking from Golang's compiler, unlike Rust, Crystal and Zig.
There is an indeed language bias and a ton of shillers going on here.
A lot of the actual Next-Big-Thing-ism seems to be coming from excited users rather than the author himself. There is a GitHub issue entitled "Very long term consideration: what it takes to get a language adopted by Google?"; there are others about getting "parallelism & concurrency for seamless local and distributed programming" and similarly extraordinarily lofty goals. People love being part of the winning project, and the overall hype history has drawn them like moths. That's OK, they can all go hang out writing V programs and wishing upon stars. It probably shouldn't bother people as much as it has.
When should we "police people feeling proud", then? Here I think there's not so much harm. Legally speaking, pretending he's in my jurisdiction (AU) for a moment, seeking donations can be trade or commerce, and then a bunch of consumer protection laws may apply, esp. ACL s 18. But you still need people who feel they've been wronged. Show me someone who tanked a heap of money into it on the pitch alone and I'll change my mind, but I don't think that's happening.
On the point of design vs actual quality, you can get an idea of OP's perspective by browsing through the GitHub issues. To be fair, the project is only a few years old, but some of the issues there are simply alien to me. It just doesn't seem like it was written in a language that has the features V has. Every new feature seems to have missed matching an enum variant somewhere. I don't understand how a compiler could exist that appears NOT to be made of building blocks that don't completely break when you add new features. I just can't relate many of the errors people get to a "Parse -> Valid Syntax -> Type Checker -> IR -> ... IRs ... -> Machine Code" progression. This is what makes me think it's not going to survive very long -- those kinds of bugs don't simply stop cropping up.
I am optimistic about the future though, so I continue writing and changing V programs (the V compiler itself is a V program mind you)... I am not in the habit of wishing upon stars (or other people), for something that requires just thinking, engineering and time.
p.s. PRs are welcome.
If I were you though, I would stick to coding, your prose is hard to read - at least try to use proper punctuation and spacing.
I have an idea, let's create a new programming language! I'll be the "ideas" man and come up with syntax ideas. You work on the compiler backend ok? And we'll split the fame 80/20 since I'm the face of the project, you know?
Edit: I would like to add that I once had your optimism and enthusiasm for my projects. I didn't quite manage to achieve them, but I got an awful lot further than most would have predicted and I learnt a great deal in the process. So all power to you.
If it's not low-level, you have to make a bunch of implementation decisions - how do your language's killer features work under the hood??
For just one example, for V, the author reuses Go's `go` keyword to launch a new coroutine/green thread. What algorithms do you use to share work between threads equally? What data structures do you use to represent those? What's the right balance between latency, throughput, memory usage, etc etc?
Many common language features are non-trivial to implement, even with the help of the LLVM IR (which I think is wonderful).
A. W. Appel, M. Ginsburg "Modern Compiler Implementation in Java" (2007)
S. Muchnick "Advanced Compiler Design and Implementation" (1997)
The last book focuses entirely on program analysis and optimization. It even has a chapter on optimization for the memory hierarchy! Of course, since it's a rather dated book, the specific details in that chapter are mostly useless today, but the rest is solid.
However, those books mostly cover imperative languages (although Appel & Ginsburg devote a chapter on functional languages, both of strict and lazy variety and discuss some optimization challenges), so if you want to learn about implementing functional languages...
S. L. Peyton Jones et al. "The Implementation of Functional Programming Languages" (1987)
A. W. Appel "Compiling with Continuations" (1992)
Holy fatcats, those are some old books! But sadly, I am not aware of more modern ones. Try searching for papers on the topics that interest you in particular, I guess (for example, there are several papers that discuss appropriateness of using CPS as IL: "Compiling with Continuations, Continued", "Compiling without Continuations", and "Compiling with Continuations, or without? Whatever". Yes, the puns seem to be the noble tradition in the PL implementation circles). The first book starts as a general introduction but starting at about the middle firmly steers into implementing a lazy languages. The second is pretty much a description of how SML/NJ compiler was made, based on its state in about 1991, of course, and has some interesting benchmarks on efficiency of different implementations of closures.
Plus, there are lot of random pages on the web with resources for various compiler implementation courses from different universities. For one arbitrary example, https://course.ccs.neu.edu/cs4410/
This project is very much in the seeking ground phase, so having a bunch of hacks is very appropriate. If it turns out useful, then people will fix things. If it turns out not to be useful, then oh well.
The danger of course if there are show stopping bugs which prohibit the transition from interesting project to useful project.
I'd be interested in hearing the critique of language, features, claims. Not sure if the implementation details are relevant to end users of language.
The author has been doing periodic reviews of the development of the language: https://christine.website/blog/vlang-update-2020-06-17
V is mostly vaporware with a lot of bombastic marketing.
Have you tried it yourself?
It takes just a minute to clone and build it, if you already have a working C99 compiler like gcc on your machine.
The V language looks beautiful (like an improved version of Go). There's always the chance someone will design something that's too complicated to develop, but that's the same with web design.
You can have a designer say, create a great UI but if they are not aware of the underlying limitations of the tech it can create a lot of headache. This may be even more relevant for language design and implementation. Ideally you have 'all-rounders' around for these issues.
It proved empirically, that compilation does not need to be slow, if the language is simple and carefully designed. Go is also a good example.
Computers are now several orders of magnitude more powerful.
We do NOT have to wait for compilation of simple programs in 2020. In my opinion, waiting is more of a symptom of the current obsession with optimization, and disregard for ergonomics, than a fundamental CS result that is set in stone. Compare for example compiling a program with gcc and tcc (without optimizations, so that they are on equal grounds, because tcc does not strive to do optimizations, but strives to be fast and tiny) .
tcc is usually 4-5 times faster.
Perhaps you could show him the way by sending in a pull request or patchset to the project to verify your expertise in fixing these 'annoying' bugs and properly writing a compiler.
Patches are welcome.
I'm curious to see how V ends up. It's unlikely that it'll succeed at everything, so eventually it'll choose a niche. And backtrack/sweep under the rug the claims that don't fit in said niche.
- As fast as C - No manual memory management - No GC - Memory safety - Not hard like Rust
You have fundamentally conflicting requirements. Saying "we'll do it like lobster" does not solve that. Lobster is essentially region based memory management with fallbacks to reference counting at runtime. That fundamentally contradicts "as fast as C". You cannot do more work than C at runtime and still be faster.
Lobster is also a different language which had to forgo a number of features V has already embraced. It's unclear how that can be rectified.
Taken from https://vlang.io/compare#go
- No global state
- No null
- No undefined values
- No err != nil checks (replaced by option types)
- Immutability by default
Looking at the repo, it looks like there is a ton of effort going on. 6458 commits and 687 open issues. Seems promising?
https://github.com/vlang/v/blob/master/examples/tetris/tetri...
https://github.com/vlang/v/blob/master/examples/2048/2048.v
You can try them with: `./v run examples/tetris/tetris.v` and
`./v run examples/2048/2048.v`
They work the same on Linux, Windows and MacOS.
fn main() { areas := ['game', 'web', 'tools', 'science', 'systems', 'embedded', 'drivers', 'GUI', 'mobile'] areas.each_with_index i { println('Hello, '+ ' areas[i] ' + developers!') } } for loops should not exist because they they are external to the an object reflection attributes.
too bad.
I assume this has mostly changed now? Has anyone tried using it recently?
That said, the project kept progressing along and seems to get daily commits, which would be unusual for vaporware.
The creator of V also seems to lack knowledge of CS fundamentals and apparently thinking he can make a great language by retrofitting "missing features" into Go.
The language is an unfunny joke.
It was like, really? You're going to have all these features that teams of engineers have been working on for decades (in many cases)? And do them flawlessly? You're also going to beat Zig, Nim, and Go - in far less time?
I've got no problem with projects like this for fun, but it's being marketed as a full fledge project.
The "only" thing missing for now is "no leaks", but we are working on it.
You may be interested in https://aardappel.github.io/lobster/memory_management.html .
> the scope of anonymous functions cannot outlive variables' scope they reference, however V plans full closure support
> lobster compiles whole codebase at once (so it can properly track data flow across module boundaries), however V plans incremental compilation support
> both points are direct consequence of lobster's choice for memory management, ie solving them would mean moving away from lobster's strategy as far as I undersand
https://github.com/vlang/v/issues/1247
Lobster's approach at least has some theoretical rigorousness to it. What V is doing is quite different both in terms of the implementation and the requirements from the language itself and they have never been shown how their version is sound.
For example, V compiles to C super fast. Then you compile the C code at normal C compilation speed. Very logical design so no complaints there, but the original claims made it sound like it went straight from V to machine code in a blink, which isn’t exactly true.
However I will say that the project has been very active, the author has made his claims a lot more clear, and so far he’s delivering on his promises little by little.
If I were to summarize my experience testing out V, I would say the author looked around at the world of software engineering and said, “there are lots of good pieces out there, but what I want is one language + Stdlib that does absolutely everything, and what the hell, I’m just going to make it myself.”
It’s super ambitious, but it’s also pretty neat.
In addition to what the sibling comment said, LLVM is a moving target. The project moves slower now than it used to, but as a general principle, the project does not provide backwards compatibility. That means there is a certain amount of constant effort required just to keep up. Even projects featured on the LLVM homepage get behind, sometimes by a large number of releases.
You're right that LLVM is better for some things. E.g. if you want to generate "real" debug info. Or if you want to generate code for GPUs, without having to teach your compiler to generate what is essentially a different language. But if you're talking about the fastest (and in many ways most stable) path to generating code, you can't really beat source-to-source with C as output.
LLVM interface is unstable.
That said there are things you can't properly implement by compiling to C.
Very interesting claim, any examples?
[0]: https://en.wikipedia.org/wiki/Threaded_code#Direct_threading [1]: https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html
This is what Nim does: https://nim-lang.org/docs/manual.html#pragmas-computedgoto-p...
• You don't control your stack and stack frames. You can't implement a segmented stack, for example.
• You have very limited options for unwinding. setjmp doesn't really cut it. You could leverage C++ exceptions or platform-specific things like SEH, but you can't design anything radically different.
• You can't have debug information fancier than #line and maybe reusing C++ name mangling. You can't make debuggers see your higher-level constructs and data as anything other than their lowering.
• You have very limited options for specifying pointer aliasing.
• If you don't want to inherit UB from C, you'll have to be very clever about using alternative constructs that don't cause UB while still compile to efficient code you wanted.
• If you mean standard C, not C with compiler extensions, then look at the whole list of non-standard intrinsics and built-ins for things C can't do.
Other points in that document are frankly baloney:
- Writing programs that pass -Wall -pedantic, Clang analyzer, PVS, and result in zero Valgrind warnings/errors is a dream of any C/C++ developer. With V it's going to be guaranteed for every V program. (We are not there yet, but very close.)
Clang analyzer is not integrated at all so this is not "very close".
Valgrind tests are mostly disabled (especially with -autofree), this is baloney.
Author has yet to set up PVS or Coverity although it was suggested a few days ago on Discord. Again, baloney.
`-Wall -pedantic` Given V can't even compile valid V programs consistently without generating C _errors_ I find this extremely difficult to believe.
> Stability. New languages using LLVM directly are going to crash often. That's inevitable, and can be seen across all new languages using LLVM. The V compiler hasn't crashed once for me, and I haven't received any crash reports from other users.
V issue tracker has lots of instances of the V compiler crashing. "I haven't received any crash reports from other users" is a verifiable fabrication. ([1](https://github.com/vlang/v/issues/6310), [2](https://github.com/vlang/v/issues/6263), [3](https://github.com/vlang/v/issues/4730))
> Simplicity. LLVM is a huge C++ dependency, meaning that both developers of the language and the users are forced to install it. Calling C++ is not easy from V/C, so C wrappers have to be used, increasing the number of dependencies and complexities.
But you need a C compiler. `v -o` requires either clang (and thus LLVM) or GCC both of which are massive dependencies. This logic rings hollow.
I personally, find the following course of events very interesting:
On 2020/09/14, a Discord user named `Engineer` writes the following:
> We should consider using Coverity as this is an opensource github project - we can test the output v filename.v -o filename.c as input for Coverity - to help us understand issues with the generated C code.
Mind you, that is not a code contributor, and his earlier questions, are about a mysterious undisclosed C compiler, that produces much more stricter error messages than gcc's ones.
Then he makes a short lecture on the topic of `What is static analysis?` again on Discord...
It is a Scooby Doo mystery indeed.
I have nothing against Coverity personally - it may very well help the V code generator, but I hate being forced to use a product in such a way.
Do you think there's a coordinated campaign by(?) Coverity to get your open source project to use it? For what reason? It's surely not to make money considering Coverity gives open source projects a free license.
> I have nothing against Coverity personally - it may very well help the V code generator, but I hate being forced to use a product in such a way.
Yes, two random people telling you to consider using a static analysis tool is "forcing" you to use a product.
----
This is a great example why everyone should stay away from V. Industry standard best practices are treated as conspiracy theories by the developers.
It's fine for people to decide they want to make a new language; that's great! It's also totally fine for all of those people to have no idea what they're doing; that's how you learn. But at some point, you need to recognize that you don't know what you don't know. V is not anywhere close to the level of production ready-ness you yourself have repeatedly claimed.
It requires a C compiler. You said it yourself. Clang and GCC are not the only existing C compilers. tcc for example is tiny compared to them - on linux, `thirdparty/tcc/` is ~4.1MB, excluding the `thirdparty/tcc/.git` folder, and ~5.8MB including it.
My personal impression was that V was an extremely ambitious project by a single developer without much experience taking on such a project, and the feature list was more of a roadmap last I looked.
There were also some head scratchers in the implementation/libraries and I recall that the playground got pwned and there was a great blog post flaming it but I can't find it at the moment.
[1]: https://twitter.com/volt_app
Take this chart, showing the selling point of "fast compilation times":
Space required Build time
Go 525 MB 1m 33s
Rust 30 GB 45m
GCC 8 GB 50m
Clang 90 GB 60m
Swift 70 GB 90m
V < 2 MB <1s
All of these programs native compilers of complex languages, supporting multiple architectures. V is a frontend for a C compiler, which is likely GCC or Clang. It doesn't even belong in the comparison.The fact that building Clang/LLVM takes 90GB of disk space is of course a sign of the impending collapse of human civilization, but I digress.
For example:
0[20:45:04] /v/nv LINUX $ ./v -x64 examples/hello_world.v
use `v -x64 -v ...` to print resulting asembly/machine code
code_start_pos = 78
x64 elf binary has been successfully generated
0[20:45:08] /v/nv LINUX $ ls -lart examples/hello_world
-rwxrwxr-x 1 delian delian 188 сеп 15 20:45 examples/hello_world
0[20:45:17] /v/nv LINUX $ examples/hello_world
Hello, World!
0[20:45:21] /v/nv LINUX $
... and yes - the generated executable is 188 bytes long...You can clone the repo, type `make` in it, then do `time ./v -show-timings self` and see for yourself - it will take you less than a minute (including cloning and the initial make which also clones from another C repository v.c, then compiles it to bootstrap v).