[HN Gopher] The Vale Programming Language ___________________________________________________________________ The Vale Programming Language Author : danny00 Score : 172 points Date : 2020-11-20 13:25 UTC (9 hours ago) (HTM) web link (vale.dev) (TXT) w3m dump (vale.dev) | skohan wrote: | Looks like inferred return type on the `planets` function on the | first page? | | I'm not a big fan of this. IMHO local inference is great, but it | makes things so much better when function signatures are | explicit. | np_tedious wrote: | I sort of agree, but enforcing this only on things public / | exported can be a nice compromise. | | (I mean this as a general statement. Idk how the language | handles this) | ccmcarey wrote: | Looking at the language ref, you can specify the return types | if you want to. | skohan wrote: | This is not that helpful if you are working with someone | else's codebase | mhh__ wrote: | D would be ruined without it. The ability to return so-called | voldemort types is not only hugely beneficial for | expressiveness but also efficiency (i.e. particularly avoiding | the heap). | | Syntax toa apply some kind of constraint to the return type | would be ok. | klodolph wrote: | When I looked up the example for D, it looks like something | that could be named with e.g. Rust's impl feature. In Rust | you can return an "impl" of an interface, which is an object | with concrete but _unnamed_ type that implements a known | interface. It similarly avoids the heap and avoids virtual | function calls, without exposing the concrete type. | | https://doc.rust-lang.org/edition-guide/rust-2018/trait- | syst... | mumblemumble wrote: | If you have a publicly visible interface, that's a name. It | may be a name of a base type but it's still a name. IIRC, | you can't even typeof() an instance of a Voldemort type. | | That has some implications for how Voldemort types work | that can't be replicated with anonymous interface | implementations. The main one is, Voldemort types are | _very_ thoroughly sealed. There is no way to create an | instance of one outside of the function where it 's | defined. With an interface, anyone else could come along | and create their own implementation. | wwright wrote: | You may be thinking of Java's idea of an interface, which | is a type (with specific subtyping behaviors). Traits in | Rust are _not_ types. There are two different ways to | reference an object which implements a trait indirectly | (actually more, but these are the dominant ones): | | - a `Box<dyn Trait>` is like a Java object referenced by | an interface. Everything uses dynamic dispatch, and it is | an actual concrete type (though the actual "underlying" | type is type-erased). | | - an `-> impl Trait` is an _existential_ type which uses | a trait as a bound, which should be equivalent to D 's | "Voldemort" types, except that it can still satisfy Trait | requires for other functions. For example, if you `-> | impl Iterator<Item = u32>`, you can pass that result to a | function expecting an iterator of `u32`. However, the | type is fully defined by the callee and can't be | instantiated/inspected externally. | klodolph wrote: | > With an interface, anyone else could come along and | create their own implementation. | | Not true in Rust, because the type returned by the | function is a concrete type. | | I think we may be overloading "name" here, a bit. If you | return an "impl" in Rust, you have to name an interface, | but you can't actually create new instances of the | concrete type returned by the function. | mumblemumble wrote: | > Rust, you have to name an interface, but you can't | actually create new instances of the concrete type | returned by the function. | | I think that's the distinction that really matters. The | thing that's neat about Voldemort types, and gives them | their interesting properties that are distinct from | anonymous types, is that they have no name at all. Not | even an interface or trait name. | skohan wrote: | What would be a concrete use case which benefits from | this? I am not experienced with D, but it just seems like | it would make code more obscure | mumblemumble wrote: | There's a bit more explanation on the D wiki: | https://wiki.dlang.org/Voldemort_types | | I don't really intend to say whether they are better or | worse than other ways of accomplishing similar things. | Just that they're different. | klodolph wrote: | Yes, from that explanation it sounds like they are | equivalent to Rust's impl return types. | | Note that interfaces in Rust are _not_ types, they do not | name types. A value cannot have interface type. What | happens when you return an "impl" type is that you return | some unspecified type, but that type must implement the | specified interface. | | You could translate the D example to: | trait HasGetValue { fn get_value(&self) -> | i32; } fn create_voldemort_type(value: | i32) -> impl HasGetValue { ... } | | The "create_voldemort_type" function simply returns a | value of _unspecified type._ As far as I can tell, this | is equivalent to the D code, except it doesn't use type | inference for the function type. | moonchild wrote: | Not really. Part of the point of voldemort types is that | no information about the type is 'leaked' outside the | function. In this case, the trait 'HasGetValue' is leaked | and can be used by other code. | skohan wrote: | When would you want to have an interface such that | nothing about the return type of a function is known to | the outside world? I'm genuinely asking; I just don't | understand the utility of this concept. | aszen wrote: | I actually like the option to have both inferred parameter and | return types, primarily because they help in writing code while | prototyping quickly with several types. | | Once the code is well defined I then start adding the type | annotations , often times using the ide tooling to auto | generate them. | | I think a good balance would be that all published packages | should have type annotations added in their source code for | clarity while short scripts could do without them. | skohan wrote: | Idk I mean maybe it's a matter of taste, but I just never | felt like it was that cumbersome to write type names in the | function signatures. In a short script it's not like you | would usually have the dozens or hundreds of function | signatures it would take to make this feel like drudgery. | aszen wrote: | Well think about writing functions inside a repl or | interactive environments like jupyter notebooks or just | plain scripting. Enforcing type annotations add little | value in those cases and end up making the language ill | suited for such use cases. | | Whole form type inference is actually a super power that | allows for writing extremely expressive code without giving | up type safety. | boboguitar wrote: | Worst part of Ruby for me, I hate inferred returns in general. | wwright wrote: | I think you may be thinking of _implicit_ returns, where the | `return` keyword is not necessary. An _inferred_ return is a | separate feature where the return type is known by the | compiler, but not stated explicitly by the programmer. (Note | that the code in question uses both.) | | Ruby, of course, technically has both as well. However, | inferring a return type in a dynamically-typed language is | probably less noteworthy ;) | optimuspaul wrote: | I was going to pop in to say that. also going to add that I | hate implicit things like this. messes with my brain, how | hard is it to just add the return keyword? saving a few | keystrokes hardly seems worth the increased cognitive cost | to others. | melling wrote: | I like explicit types on functions too. | | However, it might be what I'm used to. | | Do you think this would be less of a problem with editor/IDE | support? Using colors, or other visuals, to infer and show the | types while editing might overcome this desire. | steveklabnik wrote: | Rust did not choose to infer types in signatures for UX and | stability reasons. If you infer types in signatures, then a | change in the body of the function can change the type of the | function, which makes dealing with backwards compatibility | harder. Also, it leads to weird "errors at a distance." | kroolik wrote: | I call this property "an accidental complexity" - when | changing one piece of code causes failures in other, | seemingly unrelated parts of the system. The property | causes fear of introducing changes, and is usually a sign | of tight coupling. | skohan wrote: | I tend to agree with the philosophy that a language should | not _require_ an IDE to be productive in. | | With function signatures, I think it's particularly relevant | for documentation as well. I should be able to look at a | function signature in generated docs and know everything | about what goes into and comes out of that function. For me | the signature should be a complete contract, and changing | code within a function body should not be able to change the | signature. | aflag wrote: | The adjective modern is so popular, yet it's so devoid of | meaning. What does having a modern syntax even mean? The | impression I get when I read projects described like that is that | the authors are saying they are following the latest trends they | could find, but they don't quite know why. | zachrose wrote: | The adjective has a lot of meanings, nothing I'd call a void. | | > More common, especially in the West, are those who see it as | a socially progressive trend of thought that affirms the power | of human beings to create, improve and reshape their | environment with the aid of practical experimentation, | scientific knowledge, or technology. From this perspective, | modernism encouraged the re-examination of every aspect of | existence, from commerce to philosophy, with the goal of | finding that which was 'holding back' progress, and replacing | it with new ways of reaching the same end. | | https://en.wikipedia.org/wiki/Modernism | | Seems applicable to "modern, readable syntax". It means not | afraid to buck what people are used to if there's a better way | to do it. | simias wrote: | I think it's effectively code for "it's not like C". Easy | iteration, lambdas, generics, patterns, type inference etc... | | None of these features are technically novel but they do tend | to be shared by newer system languages, as opposed to | C/Pascal/Fortran/Cobol and friends. Then of course there's C++ | that's both old-school and modern because C++ is slowly but | surely evolving to become the programming language equivalent | of the Borg and eventually all other programming languages are | bound to become a subset of C++. | nocman wrote: | "... eventually all other programming languages are bound to | become a subset of C++." | | God help us all!!!! | | (fortunately for my sanity, I have zero confidence that this | will be the case) | thotsBgone wrote: | Every language will eventually become a subset of C++, and | they will all compile to javascript. | recursive wrote: | The modern ones will compile to webassembly. | tempodox wrote: | Via JavaScript, on the client. | marmaduke wrote: | turn it up to 11 with "truly modern" or similar. | voldacar wrote: | modern usually seems to mean means algol syntax and not having | macros :) | | aka the status quo of 60 years ago | Zelphyr wrote: | "blazing fast", "lightweight", etc... | | Buzzwords are abound in modern technology circles anymore. | | To your point; "modern" is especially insidious because it | implies that older technology is bad. I'd take vanilla PHP and | JavaScript over TypeScript and the frameworks any day. I | recognize that's an extremely unpopular opinion but those | languages are battle tested over 25 years and if I run into a | problem that I haven't seen before, there's a high probability | I'll get the correct answer from a search. For the "modern" | stuff, I get five different answers and none of them solve my | problem because the language and/or framework has changed as | many times since the question was first asked. | | That said; given the choice I'd choose Clojure and | ClojureScript. It's a young pup compared to PHP and JS but it's | still based on a 60-year old language and just a joy to work | with. | gfody wrote: | "following the latest trends" basically works as a definition | for the word "modern" in the context of programming languages. | "involving recent techniques" etc. why modern? is a fair | question I guess but why not? are there any good arguments | against things like type inference, generics and lambdas? | aflag wrote: | I see the first paragraph of a language's website as sort of | the "elevator pitch" for that language. You probably want to | cut down any vague and uneeded words in that context and | focus in the defining aspects of your language. Following the | latest trends is also vague and, the more precisely you | define it, the more you will need a timestamp next to the | term. I think it's better to jsut spell out what are the | actual features you really care about. | fiddlerwoaroof wrote: | Are any of those recent techniques? | gfody wrote: | as far as programming language evolution goes I have to | assume "recent" refers to a span of 20 years or so - | otherwise I don't think we have any recent techniques | fiddlerwoaroof wrote: | I'm fairly certain we've had lambdas (lisp) for something | like 40 years. Type inference (ML/lisp compilers) for | 30-40 years. And generics, at least in the sense of | parametric polymorphism, (Ada/C++/Java/ML) for about the | same amount of time. As far as I can tell, the borrow | checker and some features around dependent types are | newish, but actually modern features are few and far | between. | aflag wrote: | Lisp had lambdas for 60 years, I think ML has had type | inference for about 50 (maybe there are earlier languages | that had it?), ML also had generics for that long. So, | none of your examples were recent developments by your | standards. | | Even in C-like languages, generics were part of C++ (or | rather templates, in that case) since the beginning, I | think (that's 35 years ago). I think you can make a case | for type inference reaching the C language family | recently, though. | gfody wrote: | I mean sure "recent" could refer to a span of even 50 | years why not. I wouldn't trade my Roslyn compiler for | AGOL68. | fiddlerwoaroof wrote: | Comparing a compiler to a language is comparing apples | and oranges. | gfody wrote: | I disagree I think it's more like comparing an apple to | an apple tree | fiddlerwoaroof wrote: | Either way, it's hard to compare a 30 year old language | to a modern compiler because the modern compiler has | benefited from 30 years of optimizations: you can't tell | how the old language would perform with a similar | investment. | fiddlerwoaroof wrote: | As a lisper, I find "modern syntax" means "looks vaguely like C | or JavaScript" | simias wrote: | I think it's more "borrows many ML concepts but uses C/C++ | style syntax to look more mainstream, also no GC". | 02020202 wrote: | what about Zig? why so many new languages suddenly appear? | | Vale looks ok and readable(unlike butt ugly rust) but it just | tries to be really smart and I don't like it. way too much | syntactic sugar for shorter code in exchange for readability and | clarity. too many implied things...that's why Go rulez. simple, | clean, readable. | kroolik wrote: | I wonder what made the authors of the language make the pattern | matching statement keyword `mat`. Like... they were 2 characters | away from a perfectly readable name, yet they've settled up on | something that's confusing (took me a while to grasp it). Guess | the time and space savings are worth it, though. | tgv wrote: | inl, imm, mut, mat ... I see a pattern. | [deleted] | epage wrote: | There are several domains of programming with similar but not- | quite-the-same requirements | | - OS | | - Embedded | | - Game | | In some respects, these are pretty niche and there is a lot of | value imo in having a single-language that spans them rather than | creating an even more niche language for each one. I saw C++ and | now Rust filling that role. | | I've not dug into the implementation details enough to confirm | but when I see comments about runtime checks, I'm concerned there | might be things going on that make this cover only one domain | rather than covering these related domains. Even if its a matter | of "programming right" to fit all domains, that just seems | brittle. | etherio wrote: | When people build these type of languages it'd be nice if they | prominently insisted on the new approach / change the language | creates. Would be clearer. | rubiquity wrote: | It's not called out on the web page but the novel concept here is | the usage of regions for memory safety. Microsoft's Verona[0] is | also taking this approach. People seem to really like Rust but | it's important to keep experimenting and see if we can get the | same benefits but with better ergonomics. | | 0 - | https://github.com/microsoft/verona/blob/master/docs/explore... | baby wrote: | So you're saying that code you wouldn't be able to write with | rust would crash at runtime in Vale right? | zozbot234 wrote: | Rust borrowck is conservative, so not quite. There's plenty | of memory-safe programs that can't be written (or require | runtime checking) in Safe Rust. | zozbot234 wrote: | I'm not entirely sure what's supposed to be "novel" about | region-based memory management. It was featured already in | Cyclone, a C-like memory-safe language that was a heavy | inspiration for Rust. Rust ultimately went for borrowck and | lifetimes as opposed to general regions _because_ of | ergonomics. Regardless, it 's always interesting and worthwhile | to see alternate approaches being revisited - for instance, | explicit regions might help with some scenarios that currently | require unsafe{} in Rust. | moonchild wrote: | FWIW cyclone also had unique pointers. | | I don't know if explicit regions help very much with safety, | but you can certainly go places with a more expressive type | language. E.G. ats - http://www.ats-lang.org/ | simias wrote: | I don't think I understand the difference between regions and | Rust's concept of lifetimes. In my mind they were two sides of | the same coin, but you seem to argue otherwise. | | Note that my knowledge of regions comes mainly from Cyclone, | not Vale or Verona, are those different concepts with the same | name? | Verdex wrote: | My theory is that in order to replace C/C++ in the systems | language space we are going to need several different types of | languages. | | Rust is pretty nice, but the options for allocation and it's | ownership type system make it a mismatch for certain types of | applications (probably games and OS's but we'll see how that | plays out). | | I think regions are neat. And I'm looking for an opportunity | both for playing around with it myself and for the programming | language community at large getting more exposure to them. | | More ideas exposed to more people leads to better ideas of how | to fit everything together and how to leverage what features to | solve some problems better. | aldanor wrote: | Games often use arena-based allocation systems, slotmaps etc | to manage myriads of instances. I don't see how any of that | is a problem in Rust? | megameter wrote: | It's mostly the ergonomics of Rust being fine-grained that | present a problem. While it's gotten better with revision, | fundamentally, you start in an assume-nothing mode in Rust | and then boilerplate appears to say "actually, this one is | mutable". This incurs friction on nearly every line of | state manipulation and when you're doing game-style | allocation, you mostly don't care. You have a tremendous | amount of mutable state; some of it you blow away every | frame, the rest you may want to lock sometimes. | | What Vale does that is attractive is to make simplifying | assumptions that address this problem domain closer to the | level of granularity that it deserves. | danbolt wrote: | I think a pure ECS has its state manipulation well- | encapsulated and organizable. Part of me thinks that sort | of design would mesh pretty well with Rust's ownership | system. | steveklabnik wrote: | Rust folks think this as well; there has been a _lot_ of | activity in this area, and even spread some of the ideas | behind ECSes to areas outside of games. | | https://kyren.github.io/2018/09/14/rustconf-talk.html | steveklabnik wrote: | It is not. The usual arguments against Rust for games are | more cultural. Rust makes a tradeoff of being a bit harder | up front, for less time debugging later. Many people say | that games specifically would prefer the opposite tradeoff. | | We'll see as things continue to develop here. | ampdepolymerase wrote: | A modern alternative to C's FFI needs to be developed, | perhaps a standard like gRPC but as a compiler extension. C's | FFI contains so little information due to its weak type | system that it is wholly unsuitable for higher level | languages. Yet we use it because it is the lowest common | denominator. The C FFI has cost hundreds of hours of lost | productivity due to having to re-annotate all the types in | the non-C caller. This is before we even take into account | the mess that is function pointers and types generated using | the pre-processor. And no, tools like bindgen and c2rust are | stop gaps, not a real solution. A lot of low level code | cannot be effectively called safely in a higher level | language at all without hundreds of hours of manual work | wrapping and annotating each individual function. We need a | new standardized, zero cost, cross language interop format | that functions on the ABI/memory level. Rust's Cxx is a good | start but it doesn't scale m:n with regards to new languages. | Every new language has to implement a custom wrapper for | calling another high level language if they do not want to | lose 80% of the benefits of the respective language's type | system when passing through the primitive C FFI. For example, | calling Rust from Julia, calling Julia from V lang. The lack | of a common interop format is hurting the developer ecosystem | as more proliferation of programming languages simply leads | to greater fragmentation. The web solved this a long time ago | with JSON APIs, generated OpenAPI clients (and now Graphql), | and to a lesser extent, gRPC. We need to do better when it | comes to systems programming. | 10000truths wrote: | The whole _point_ of FFI is that it 's a lowest common | denominator - it's a _foreign_ function interface, meant | for interop between two potentially wildly different | runtimes, up to and including assembly language. That means | it can 't rely on quirks like language-specific type | information or bounds checking. The only thing that all | runtimes on a machine are guaranteed to have in common is | that they use the same set of memory and CPU registers, so | that is all that FFI can use to define subroutine | interfaces. Hence terms like 'ABI', 'calling convention' | and 'memory layout'. | | The good news is that whatever issue you have can probably | be solved without resorting to FFI. There are plenty of | other interop options - for example, if you control the | library, you can use your operating system's IPC mechanisms | with an agreed-upon serialization format. Or, if your | library and application are within the same ecosystem, you | can use language-specific library management features such | as Python's import or Rust's crates. FFI is a bit like C | itself - if you're reaching for it as a solution to your | problem, then your finger is already on the trigger of the | footgun. | ampdepolymerase wrote: | And most people used to believe that ergonomic, zero cost | memory safety was impossible too. And yet it moves. There | is no reason why we have to settle for a poor FFI | solution just because it was the choice of our | predecessors. | 10000truths wrote: | Memory safety and FFI operate on two different layers of | abstraction entirely. What does it mean to enforce | 'memory safety' across the boundaries of two different | applications/libraries that may have entirely different | ways of keeping track of memory allocations and | deallocations? Again, FFI has to be agnostic to such | implementation details in order to work, and it does so | by forcing you to define interfaces in terms of the | lowest possible level of abstraction common to all | applications. That means explicitly specifying expected | memory layout and calling convention on both the | application and library sides, i.e. an ABI. | jrumbut wrote: | IPC is, I think, the concept that has been neglected and | led to the desire for some kind of really intelligent | FFI. | | If you have code in Ruby and in Julia that you want to | mix together it's probably because both pieces of code | leverage the distinct capabilities of those two | languages, which have nice capabilities because they | accepted very tradeoffs. | | Would you really want Julia with Ruby's Number class? It | would entirely kill performance. You want it to be an | integer maybe, or a double, or sometimes something else. | It's going to be application specific is the point, | because another user want some different subset of | Number's behavior. I don't think there's a shortcut here | besides making a very limited or opinionated FFI system. | rng_civ wrote: | I think there's a conflict between FFIs in practice and | theoretical FFIs. The few papers I've read for sound FFIs | between languages A and B rely on the fact that the | common interop target is a high-level language whose | features subsumes the features of A and B. ABI, calling | convention, etc. are merely implementation details. | | So from this perspective, the interop target should | actually not be the lowest common denominator, but the | opposite: a target that can describe all possible user | languages in a common format. | | In fact, I would actually argue that the implementation | details are NOT that interesting and only a distraction: | that we need an abstract way of declaring compatibility. | For instance, one can imagine a high-level FFI target | where function types are parameterized by their calling | convention i.e.: | | `foo: (VOID<C>->VOID<C>)<C>` | | `bar: (UNIT<Rust> -> UNIT<RUST>)<RUST>` | | and attempting to call `bar` from `foo` involves a | compiler intrinsic like `RUST_CALL(bar)()` to convert the | type (and the calling convention) appropriately. | chubot wrote: | This is a very real problem, particularly the M:N issue. | | But I think it's inevitable you have to do things on both | sides of the language boundary, i.e. pushing them towards a | lowest common denominator. (e.g. Microsoft's COM, which | actually worked pretty well) | | Really what it pushes you toward is wire protocols and NOT | relying on the type system. That is the C and C++ ABIs are | related to but different than the APIs (type system). | | My experience tells me that transparent interop is kind of | a pipe dream. The problems always pop up somewhere. By | "transparent", I meant "Rust function calls C++ function" | and "C++ function calls Rust function" without other | metadata/bindings. The codegen becomes a big problem in | practice. | | Fundamentally a lot of languages LOOK the same but they ACT | completely differently. A Rust function is not a C++ | function is not a Python function is not a Go function. | (And funny thing -- as of C++ 11, C++ now has many | different notions of "function", because of move | semantics). | | And functions are actually "easy" compared to types (e.g. | inheritance vs. typeclasses vs. interfaces) | | ---- | | Basically I would say the problem is that you either spend | time manually wrapping or annotating your code (as you | say), OR you put an ever growing list of heuristics in the | code generator, a la SWIG. | | Those heuristics have bugs, and will make your program | unreliable. They're also "someone else's problem", which | leads app developers to come up with horrific workarounds. | | So I go with the simple manual wrapping, and reducing the | number of things to wrap by changing the structure of your | program. This also has other benefits like efficiency, i.e. | crossing the language boundary less often. | | (Related: I think better build systems can go along way | toward solving this problem. Unfortuately there seem to be | a lot of language-specific build systems and package | managers now, which only exacerbates the interop problem. | If you have one language-neutral build system, it's not | that bad.) | simias wrote: | >We need a new standardized, zero cost, cross language | interop format functions on the ABI/memory level | | I don't think that's doable unless the underlying language | already has the same ownership and lifetime guarantees as | Rust does, otherwise these bindings have to protect against | memory issues by effectively taking ownership of the data | to garantee its lifetime, which is not zero cost. | | I simply don't think that you can auto-generate zero-cost | safe C or C++ bindings automatically. | estebank wrote: | > I simply don't think that you can auto-generate zero- | cost safe C or C++ bindings automatically. | | As stated, that's likely an accurate statement, _but_ if | you separate the requirements for the bindings the | problem looks _way_ more tractable: | | - auto-generate: I'm pretty positive that this point is | only hard given the following, and I feel you would agree | with that assessment, so I'll just focus on the other | ones. | | - zero-cost: doing zero-cost ffi is the best option, but | a lot of advanced constructs that people want to use | cannot be well represented in that way because they rely | on the internal consistency of the host language. That | means that dynamically loading a library written in Rust | might make it so that you can _only_ interact with ADTs, | trait objects and whitelisted provided traits on those | ADTs, potentially only through trait objects. That 's not | zero-cost, but it is super powerful. ObjectiveC has lived | its entire existence going through vtables and that has | even enabled runtime introspection that was super useful. | | - safe: safety can be accomplished easily enough if you | don't constrain yourself to zero-cost _or_ if you put | constraints on _what_ is supported for zero-cost ffi. You | could say that method calls on trait objects is safe, but | type parameters are out of scope because ffi and | monomorphization are not compatible. You could restrict | yourself to either no borrows crossing ffi, or no mutable | data (only internal mutability through trait methods) | allowed. | | - C or C++: I would focus on _other_ languages, | personally. Having easy interop with Java, C#, Python and | JavaScript would open opportunities that do not have | anything to do with systems programming per-se, but that | would make it more likely that the next numpy isn 't | written in pure C. | | - automatically: the need for extra annotations in either | end of the interop simplifies part of the problem and | might even help with documentation. Adding some light | ownership information to APIs in non-Rust languages would | be great for non-Rust users of those APIs. | bee_rider wrote: | Hey! Surely there's some Fortran left in some of the | libraries that back NUMPY. | dgb23 wrote: | > People seem to really like Rust but it's important to keep | experimenting and see if we can get the same benefits but with | better ergonomics. | | Is my intuition correct that one could implement this type of | memory handling in Rust as well? | thechao wrote: | I'm drawn to regions because they seem to intuitively match how | I write my high performance systems software. In those sorts of | SW, I really need precise and cheap ownership rules, but | without any restrictions in topology. | | It'd be super if regions were a mathematically robust way of | describing that engineering solution. | tomp wrote: | From my reading of the docs, Vale is _not_ memory safe. It | offers some tools to _assist_ with memory management, but is | fundamentally closer to the safety level of C++ rather than | Rust. | rafaelvasco wrote: | Not being fully memory safe but assisting in it, is the way | to go for the broad scope of applications imo; | vlang1dot0 wrote: | I don't really agree. The vast majority of applications are | fine being written in whatever flavor of high-level, | garbage collected, memory safe language you want. There are | many nice options with pretty much any set of feature and | style choices you could want. | | The rest of these applications have either hard realtime or | hard performance requirements or both. What I don't see in | these apps, is for memory safety issues to be 'ok'.* It's | 2020, using a memory safe language should be table stakes | for new projects at this point. | | ---------- | | * The one exception I can think of is single player video | games where the worst that can happen is basically just a | crash to desktop. Multiplayer games are a different story | especially with the trend toward paid DLC where these kinds | of issues could result in anything from exploits in | multiplayer matches (hurting the community and thus the | game overall) or players circumventing DLC restrictions | (resulting in a loss of profit). | mansoor_ wrote: | Language looks Rusty :) | hhas01 wrote: | Well this is it, isn't it. Because really, what the hell _is_ | its USP+? The world already has a perfectly cromulent Rust | language. Adding a second, less popular one merely dilutes both | efforts; and to what purpose? Ego? Control? Simple | unwillingness to accept a direct competitor has _already_ | beaten their ass to market and mindshare? | | Everyone knows the name Charles Darwin. Now ask them who Alf | Wallace is, and why they should they should care. Or Yohan | Blake. Or Atty Osborne... and so on. | | Where's the advantage in being an also-ran? It's a tough but | necessary lesson to swallow: accept your lovely technology is | just too late to be the successful product you hoped for. Treat | the whole exercise as a valuable learning experience, and move | on to your next Big Idea as quickly as you can, this time, of | course, making sure to get to market _before_ your direct | competitors can, so as to leave _them_ in the dust instead of | you. | | -- | | + Their website doesn't say. Just a technical features list, | and yep, one look: Rust, but a lot less mature with waaay less | ecosystem and support. That's not a winning proposition; that's | a sucker's deal. Damn but every computer geek needs to do a | marketing course. | lopatin wrote: | Upvoted because I'm pretty sure this comment was written by a | neural network. Commented because I'm hoping for a reply. | hhas01 wrote: | Negative, I am a meat popsicle. | ddalex wrote: | All comments are written by neural networks,in the end. | [deleted] | ddalex wrote: | > Simple unwillingness to accept a direct competitor has | already beaten their ass to market and mindshare? | | I have not seen any shred of competition suggestion here. But | even if there is competition, that should be encouraged - | competition is healthy, and it promotes development. Who is | to say that Rust has all the good ideas and nobody else can | have any good idea ? | | You should encourage competition not stiffle it "because | somebody else is more advanced" | nicoburns wrote: | I had to do some digging, but I found this: | | > A memory model and first-class regions which together make | it as fast and safe as Rust, without the borrow checker and | its aliasing restrictions. | | (https://www.reddit.com/r/vale/comments/i95ue8/use_case_of_th | ...) | megameter wrote: | You're showing a lot of attachment here. Rust is not your | precious child in need of defending by attacking upstarts. | There are many tools of this kind and there will be many more | to come. | hhas01 wrote: | I'm not a Rust user. I have no particular nag in this race. | What I do understand, or at least am start to learn, is the | difference between a Technology and a Product, and between | a Product and Success. | | So once again: What is Vale's USP+? Because it isn't on | their frontpage; which it would be had they thought to ask | that question of themselves. | | -- | | TL;DR: Goddamn it, all you noobs, but learn _How To Sell_ | already. Some of us are just too damned old and tired to | want to hold your diapers till you learn to grow up. Try | making our lives a bit easier for once; not just to benefit | us but your own products as well. | | . | | (+ And if you don't even know what "USP" means, well there | you are. As someone who has already tried to bring truly | groundbreaking new tech to market and flubbed it, and is | just about to roll up sleeves and try, try again, I'm not | asking these questions just to be obtuse but to be | _helpful_. However, if you'd rather just insult than ever | amount to squat then by all means carry on.) | creata wrote: | I don't know what Vale's "USP" is, and I think you're | right to point out that it doesn't really sell itself on | its front page. But you're being a _massive_ dick about | the marketing of a language which is clearly a work-in- | progress, and hasn 't even hit v0.1. You know you can | give advice _and_ be nice about it, right? | hhas01 wrote: | Why? Will the _market_ be any nicer to them? They've | failed to make their case as to why _anyone_ should care | that Vale exists; never mind actually differentiate it | from the current swathe of robust, established Rust-style | languages _already_ in full production use and battling | each other for the market's next 20 years of attention. | And they've barely reached v0.1, and expect to make a | difference when make their grande entrance into that | bullpen? Who's fooling who here? | | Look, if they just want to be another D then by all means | have at it. It's great that they have a personal hobby, | but at least have the good grace to put up a notice | saying they're making this thing to please nobody but | themselves. That way anyone else looking at it knows not | to invest their own time into a toy project that doesn't | even take itself seriously, never mind have the chops to | make the rest of the world believe in it too. | | Oh, and by the way, I've said nothing about Vale that | I've not said of my own projects... right before I've | pulled the plug on them for failing to hit their overall | objectives. And the best of that work's been technically | excellent, with sitting users royally pissed that I've | just chucked their investments on the scrapheap along | with my own. But I'm a realist; and it's better to pull | the trigger now and move on ASAP to the next thing, than | drag out a slow but inevitable death and then have to | junk an even larger investment further down the line. See | also: sunk cost fallacy. | | You want to ask other people to believe and invest in | you? You'd damn well better bring more than just a tick | list of features and your delicate feels. Else you're | just messing them around for your own personal ego. | | /fin | | -- | | TL;DR: When someone offers you difficult questions and | brutal honesy, take it and ask for more, 'cos that's the | best gift they can offer. But if all you want is a pat on | the head, then go ask your mom as I'm sure she thinks | everything you do is wonderful. | voldacar wrote: | I don't want to sound mean but I think the world has enough algol | clones already :/ | jbotz wrote: | I admit that I also automatically lose a bit of interest if I | see "familiar C-like (algol-like) syntax" as a supposed feature | in a new programming language, there is also no point in being | original just for originality's sake, and the space of possible | syntaxes for programming languages has been pretty well | explored. But in terms of semantics this really doesn't look | much like an "Algol clone" at all, rather it seems to want to | explore the conceptual space between imperative and functional | languages where Rust has been breaking genuine new ground, and | which clearly has more room for experimentation. | rienbdj wrote: | Having spent time with languages that use c syntax and ones | with whitespace based syntax, I much prefer the latter. I | think c syntax is seen as plus not because it is better, but | because it is familiar to more people. See also ReasonML | spijdar wrote: | Just for a dissenting opinion, I use both types of scope | syntax on a regular basis and prefer the Algol-ish one. I | _personally_ find it easier to reason about where code | blocks begin /end when they're explicitly marked. Makes | moving code around easier, too. | | Note that most of my problems could be fixed with enough | tooling/editor plugins/IDE magic, I just don't use them. | rayman22201 wrote: | Nim tried regions based memory management and ended up going a | different direction. The feature still exists, but the core devs | ended up considering it a bit of a dead end: https://forum.nim- | lang.org/t/6930 | iphorde wrote: | Why do we need to denote a function, with fn, def, function, ...? | we can do better than this. | Groxx wrote: | main() { something() { // implementation | block for something(), or anonymous scope? } | something() // first or second execution? } | iphorde wrote: | something() { } obviously is a definition, something() is | obviously a call. | | Why is that hard for you? | Groxx wrote: | or is it obviously executing `something()` followed by an | anonymous scope with a less-common indentation pattern, | e.g. equivalent to var x = 1; | something(); { var x = 2; } // x | is now 1 again, as the scope // containing the new | variable x=2 is gone something(); | | or, as mentioned in another comment, is it passing an | execution block to `something()`? (I didn't mention that in | my original since it's a bit less common of a language | feature, but it's valid too) | | enforced semicolons and/or significant whitespace/newlines | can resolve this in some cases, but it of course depends on | the language. and diverging too far from common langs has | its own downsides too, especially where you're changing the | interpretation of what are already common patterns. | steveklabnik wrote: | That is actual Ruby syntax for an invocation of something, | so it may or may not be obvious depending on what you're | used to. (Though most Rubyists would drop the ()s) | | Also, as mentioned, in many languages it is valid syntax | for an invocation of something, followed by a new scope. | rafaelvasco wrote: | Perfect answer; | [deleted] | adamnemecek wrote: | The project has a discord channel for those interested | https://discord.gg/SNB8yGH | _zachs wrote: | Interesting! Is this supposed to be an easier-to-read Rust? | [deleted] | jgilias wrote: | Can someone give a quick TLDR what are the main differences to | Rust? | | EDIT: Or rather, what are Vale's selling points to someone using | Rust? | duckerude wrote: | One core difference seems to be that references are checked at | runtime. In Rust you have to be able to prove that a reference | to a value can't outlive the value, but Vale is more trusting, | and simply crashes if a reference outlives the value in | practice. | | You have constraint references, which crash the program if they | still exist when the value is freed. And you have weak | references, which turn into null. Constraint references can | optionally be compiled into raw pointers. | [deleted] | merelydev wrote: | The author posted this on reddit [0] a few months ago: | | Vale's main goal is to be as fast as C++, but much easier and | safer, without sacrificing aliasing freedom. It does this by | using "constraint references", which behave differently | depending on the compilation mode: Normal | Mode, for development and testing, will halt the program when | we try to free an object that any constraint ref is pointing | at. Fast Mode compiles constraint refs to raw | pointers for performance on par with C++. This will be very | useful for games (where performance is top priority) or | sandboxed targets such as WASM. Resilient Mode (in | v0.2) will compile constraint refs to weak refs, and only halt | when we dereference a dangling pointer (like a faster ASan). | This will be useful for programs that want zero unsafety. | | Vale v0.2 will almost completely eliminate Normal Mode and | Resilient Mode's overhead with: Compile-time | "region" borrow checking, where one place can borrow a region | as mutable, or multiple places can borrow it as immutable for | zero-cost safe references. It's like Rust but region-based, or | Verona but with immutable borrowing. Pure | functions, where a function opens a new region for itself and | immutably borrows the region outside, making all references | into outside memory zero-cost. "Bump calling", | where a pure function's region uses a bump allocator instead of | malloc/free. | | [0] | https://www.reddit.com/r/ProgrammingLanguages/comments/hplj2... | [deleted] | scott_s wrote: | The author also compares and contrasts at the end of a blog | post: https://vale.dev/blog/zero-cost-refs- | regions#afterword:borro... | cryptograthor wrote: | Looks like a language heavily influenced by Rust! I'm interested | to see if we see more drift in this direction. Rust's by no means | conquered the world (yet), but things keep moving in that | direction, I'm curious if we'll see looser or otherwise quick-n- | dirty (https://users.rust-lang.org/t/prototyping-in-rust-versus- | oth...) Rust-like languages | [deleted] | xeeeeeeeeeeenu wrote: | Not to be confused with Vala: | https://wiki.gnome.org/Projects/Vala | jopsen wrote: | Wow, that's an extremely poor choice of name for a programming | language. | | I was 100% sure this was the gnome thing. | oscargrouch wrote: | In portuguese 'vala' is the hole you dig on the ground or a | naturally occuring one. Which can also be used as a synonym | to "cova" which translates to "grave". I bet it will be hard | to make a community for it here in Brazil or Portugal. | xeeeeeeeeeeenu wrote: | People overestimate the impact of brand names having weird | meanings in foreign languages. | | For example, OSRAM unambiguously means "I will shit" in | Polish, and despite that, it's one of the most popular | lightbulb brands in Poland. | Lapsa wrote: | too late | qalmakka wrote: | Even though I think the market for programming languages is | saturated and it will be for the next decade or more, I think | it's always nice when someone tinkers and creates something new, | so, my congrats to the authors! | mikewarot wrote: | There is plenty of idea space to explore in programming | languages. | | ColorForth, for example... lets you do some of the work a | parser would do, at edit time, by adding additional attributes | to the source. | | Verilog, Ladder Logic, and Register Transfer Language all allow | the programmer to specify a flow of logic and expressions that | is always running, instead of a flow of instructions that we're | all used to. Mixing this paradigm with the traditional code | we're used to offers powerful possibilities. | | Transforming spreadsheets to a set of statements that are | always executed, and vice versa could be fruitful as well. | zomglings wrote: | It's important not to think of it as a market. It is pretty | valuable (and not in terms of dollars right now) to create | things like this. | mumblemumble wrote: | The market for programming languages has been saturated at | least since I got into programming. Which was not all that | recently. | | The market for music has been saturated for even longer. But | nobody really complains when someone wants to start a band, | because we recognize that creative work has intrinsic value, | even when it produces little economic return, even if only by | enriching the life of its producer. Experimenting with | programming languages is only very superficially different from | that. | neutronicus wrote: | No reason to complain until people start bugging you to go | see their band or use their programming language. | dgb23 wrote: | I think this is a weird way of looking at it. | | PL are evolving continuously on some level or another. New | languages pop up with new concepts or ways to do things, old | languages can then incorporate some of these things. | | It works with all things similarly, there is a conventional | main-stream that most adhere to, for efficiency gains but the | creative risk takers are the ones who drive things forward, or | fail to do so. | qalmakka wrote: | Yes, I mostly agree with you, but I think that if we look | closely to how programming languages have evolved over the | years, we can more or less define them into "generations" | i.e. periods where certain concepts have more or less | dominated the interest of the community and have dictated how | software and languages in general are designed. | | These are usually linked with one or several languages | springing out and becoming popular, either by embracing new | paradigms or by strongly rejecting a mainstream concept whose | usefulness have been cast into doubt either by the industry | or the community. | | Outside these periods, the overall interest tends to stagnate | while the newer languages become stable and gain mainstream | acceptance. In such a situation, a new contender must either | find itself a niche, by covering very specific needs in very | effective ways, or it must compete in mindshare in order to | justify itself among the newest big names (i.e. any new | compiled, strong typed and memory safe language nowadays is | almost forced to compare with Rust and I dare say Zig). | | That's what I meant with "market saturation": I think the | stagnant landscape of the 00s, dominated by classic, OOP | languages, gave birth to a huge wave of "safe" languages in | the 10s, many of which share similar concepts and ideas; I | think we're now in a moment where some of these have made a | name for themselves and have been established as mainstream, | serious solutions (see Rust or Go), requiring newer | contendents to be really innovative in order to capture | mindshare and not be considered "me too" languages. | | These are, obviously, just my two cents; I really love | compiler development and language design, and I think we | should always support new languages and the work people do | towards the goal of designing better languages and improving | existing ones. | mikewarot wrote: | Why would a programmer ever worry about "ownership"? I've never | had to do that. | freeone3000 wrote: | Garbage collected languages (Java, JS) have significant | overhead, and unpredictable latency spikes. | | Scope-based memory management (C++) has copying overhead and | destruction overhead, and a whole lot of complexity to avoid | those. | | Ownership-based memory management removes most of the overhead | associated with copying and destruction in a less-complex | fashion. | ben-schaaf wrote: | Note C++'s semantics are akin to ownership, it just has | different defaults and none of the safety guarantees. A | std::vector is owned by the current scope, ownership can be | passed around using std::move and references can be taken | using &. | rwmj wrote: | _Bad_ garbage collector implementations, but not GC in | general. malloc /free can have latency spikes too. | | Also not every programming problem in the world is a memory- | constrained hard real time problem - in fact, I would say | almost all of them are not. | | Memory ownership is certainly an interesting thing to have in | your arsenal, but a whole class of problems (especially | anything with a graph or modestly complex interlinked data | structure) can't easily be reasoned about using this model, | or you end up copying stuff anyway to get around the borrow | checker. | | Having said all that, I'd really like to see a language that | lets you use a garbage collector 99% of the time for ease of | use, but allows you to use other models for the small | sections of the code which need it or within certain | designated real time threads. | vips7L wrote: | You're looking for D! | | https://dlang.org/spec/function.html#nogc-functions | megameter wrote: | I beg to differ. For a sufficiently large time scale, | _every_ programming problem is a memory-constrained hard | real time problem. | mhh__ wrote: | D let's you do that if you want. | mhh__ wrote: | Ownership is a conservative restriction of allowed behaviours | (i.e. rust still has ref counts), the three approaches don't | do exactly the same job | ben-schaaf wrote: | Then you haven't ever written a line of C/C++ I presume? | Ownership is just a formalization of the way almost all | resources (including memory) are managed in C: A single | function has the responsibility of doing cleanup; that | responsibility can be moved around to other functions of | course, but only one ever has that responsibility at a time. | mikewarot wrote: | >Then you haven't ever written a line of C/C++ I presume? | | Correct... I'm a Pascal programmer. I create objects when a | program starts, delete them at the end. I've never really had | any of the pointer problems that seem to plague C/C++. | wwright wrote: | I assume you write fairly "static" software that knows its | job pretty well in advance. Ada programs tend to use a | similar allocation strategy. | | A lot of programs written in C and C++ are _very_ dynamic, | and may need to massively increase or decrease the number | of objects they use while running. For example, consider an | audio workstation: when you first start it, it has very | little to do, but the user can add literally hundreds or | thousands of tracks, each with dozens of effects and | modifications. | | Each of these features is composed of many objects. | _Ownership_ comes in when these objects have complex | relationships, where one object may need to be referenced | by many others. When it is time to clean up some of these | objects -- for example, when a user deletes a track in the | audio workstation -- you have to know _which_ of these | shared objects to delete. Ownership is one way of modelling | that problem. | | Languages that talk about ownership try to optimize the | "best case" where an object has exactly _one_ owner, | because then it 's very simple for the compiler to free | that object. The trick is that you have to _prove_ that no | one else is using it, or else you have memory errors. | pwdisswordfish4 wrote: | > Correct... I'm a Pascal programmer. I create objects when | a program starts, delete them at the end. | | Then I guess you should instead say you're a 'single-shot, | compiler-like batch job executable' programmer. I imagine | that colours your perception more than the choice of | programming language itself. If you were to write a program | that has to manipulate deeply nested data structures, or a | long-running service that has to acquire and dispose of an | unbounded number of various kinds of resources over the | course of its runtime in a deterministic manner, you'd | start longing for an ownership system very quickly. | mikewarot wrote: | I'm trying to imagine when I'd worry about ownership. The | only thing that comes to mind for me is having to provide | buffers for string results from OS calls, etc. In Pascal, | you can return a string, assign it, append it, etc.. and | never have to allocate/dispose of them... its taken care | of under the hood by automatic reference counting. | | I'd really like to understand this... what specific type | of thing were you doing when you found yourself longing | for an ownership system? | | [edit] It occurs to me that anytime I have objects, they | eventually trace their ownership to a single global | variable. Perhaps that has something to do with this? | steveklabnik wrote: | It is an alternative, in many cases, to automatic | reference counting. It's sort of like saying "why would I | need automatic reference counting? I have a tracing | garbage collector." | mikewarot wrote: | That makes sense... thanks! | | So, in general, if something is too big to fit to easily | be copied, or stored in a single variable of known size | (like strings, dictionaries, lists, trees, etc.) its | either GC or ARC to the rescue? | steveklabnik wrote: | No problem. :) | | That's not _quite_ it. It 's more about compile time vs | runtime. Arc and GC are _runtime_ tracking of "when can | this be freed." Ownership is compile-time tracking of the | same. Rust has refcounted types in its standard library, | but you only need to use them relatively rarely. Here's a | small example with not _too_ much syntax. The core idea: | fn main() { // String is a heap allocated, | mutate-able string type let s = | String::from("foo"); } // s goes out | of scope here, and so will be freed here; // | the compiler generates the code to free the heap | allocation at this point | | s is the "owner," and there's only one, so this can be | tracked fully at compile time. | | Onwership can move, too. Let's introduce a function: | fn foo(bar: String) { // body would go here, | elided to keep this simple } // | because bar is of type "String", this function "takes | ownership" of the // value passed as 's', and | so the compiler will generate the code to free | // its heap allocation at this point fn | main() { let s = String::from("foo"); | // we pass s to foo... foo(s); | } // ... and because we did, it no longer exists in main, | and the compiler // knows this, so no code to | free the allocation is generated here. if // it | were, this would lead to use-after-free. | | All of this is trackable, 100%, at compile time. So | there's no runtime overhead here at all. | | But imagine that foo() creates a new thread inside of it, | and we want to access said string from inside that | thread, as well as from within main. Now we have | _multiple_ owners, not a single one, and it 's not | possible at compile time to know when the string should | be freed. The simplest solution here is to reach for | reference counting, and you'd end up with Arc<String>, | that is, a String that's wrapped in an atomic reference | count. | | (Also, references _don 't_ take ownership, so if you | didn't want to have foo free its argument, you'd have it | accept a reference, rather than a String directly. This | would let you temporarily access the string, without | freeing the backing storage when the function's body has | run its course. | adamnemecek wrote: | The examples are numerous but for example databases or | GUI frameworks. You end up in situations where a parent | needs a reference to a child and child needs a reference | to its parent and it gets unwieldy. | randomNumber7 wrote: | > Correct... I'm a Pascal programmer. | | Real men don't use pascal ;) | | Have you ever closed a file? | epage wrote: | So everyone else is focusing on the memory allocation side of | ownership. The other side to this is aliasing / borrowing / | handling references and mutability. | | In Python, you might have a `list` that you built up and them | pass its data to multiple functions. You assume these functions | are do not mutate their arguments and you keep passing the same | `list` over again. In this case, the caller is controlling the | invariants of the `list` and therefore "Owns" it. | | Deep down, one of those functions needs to mutate a `list` to | do its calculations. Where the mutation is happening, it | assumes it is the "Owner" and can modify the `list` without | violating any invariants. Unfortunately, a "Borrowed" list was | passed in and now the caller's invariants are violated. | | Rust's ownership model helps to catch this kind of problem at | compile time. By default, everything is single-owner though you | can change that with a `Mutex`. | creata wrote: | Yep. Even when you're doing something as simple as iterating | over some data structure, you have to remember not to mutate | it. Rust enforces that, but Python just either corrupts the | data structure / iterator, or _if you 're lucky_ it'll throw | an exception. | ycombonator wrote: | Valid question. if you started programming dynamic languages | like Python you don't have to worry about memory control. | kzrdude wrote: | It's an object lifecycle concept. | | You worry about ownership if you have a resource and need to | think of when to free/dispose/close it. | | You worry about ownership if you have an object that many have | a reference to, and some of the references shouldn't keep the | associated resources alive, and some other of the references | should keep it alive. Those that keep things they referenced | alive are (shared) owners. | mhh__ wrote: | https://xkcd.com/371/ | hhas01 wrote: | Also: https://xkcd.com/927/ | krisoft wrote: | It's a memory safety concept. | | In languages like C you allocate memory yourself, and then you | have to make sure to free it up too. This is error prone. | | In garbage collected languages like Java there is a garbage | collector who figures out when is a piece of memory no longer | in use. This has run-time cost. | | The third possible way is to make the ownership of that part of | the memory explicit. This way the compiler can check memory | safety at compile time. | | There is a much better description of this in the Rust book: | https://doc.rust-lang.org/book/ch04-01-what-is-ownership.htm... | itwy wrote: | Isn't this the same language heavily used by ElementaryOS devs? | rudedogg wrote: | You're thinking of Vala (https://valadoc.org/) not Vale. | itwy wrote: | Ugh ridiculous naming then | detaro wrote: | nope, that's Val _a_ | z_kro wrote: | Sounds good, but the name may confuses it with Vala | https://wiki.gnome.org/Projects/Vala | tempodox wrote: | Is it interpreted or compiled, AOT or JIT, native or byte code? | The landing page doesn't say, but I'd like to know such details | and a host of other information that isn't mentioned either. All | this doesn't motivate me to dive deeper. ___________________________________________________________________ (page generated 2020-11-20 23:00 UTC)