Gravity: a new programming language and VM written in C
github.com
github.com
dynamic typing (not a fan myself, but for scripting: OK --- would be great if all such languages had a statically&strong-typed option --- after all the compiler/JIT needs to guess/work much less)
higher order functions and classes
coroutines (via fibers)
closures
garbage collection
operator overriding
powerful embedding api
Very neat-sounding. Will have to keep watch. Not as low-level as Go (can become wordy!), not as "foreign" initially as Rust (what, no GC, borrowing, a borrow checker, what?), not (yet!) as "haphazard" as... the majority of shell-scripting/server-scripting/client/web-scripting approaches.So I guess I'll stick with TypeScript or C# for writing my cross-platform apps. The ecosystems for both are much more robust anyway.
I agree that strongly & statically typed languages allow for and indeed yield more robust ecosystems and complex apps.
But scripting languages have their place, roughly at the level of bash/.sh/.bat scripts IMHO .. the issue is that as LoB apps evolve from "simple one-off experiments" and "just a quick'n'dirty prototype to see if-and-how" to "mission-critical infrastructure" there just seems to never be a good time for anyone to say "we stop here, let's transfer this to a more stringent language early on first now, better today than too late".
Best would be if "scripting languages" actually had Haskell levels of type inference, even if not the rich type system, this way there wouldn't be type annotations (just like in scripting) BUT with a toggle-able "scripting-like lenience" that can be turned off to make the type-checker brutal, or initially during prototyping/scripting turned on by default to allow for ambiguous / uninferable / defer-to-runtime-and-allow-unsafe-conversions RAD-style work. With an additional middle-ground setting where it's still lenient but emits console warnings to review potentially troublesome sections.
Someone should create a whole new scripting language just for that! Any takers?
I also use functional concepts, and my code also ends up with lots of nice, composable blocks, but being in a language that forces functional concepts where they don't fit is a recipe for unneeded complexity and unintuitive code.
Functional isn't a silver bullet. There Is No Silver Bullet.
Exactly, though the dynamic languages like Python did reveal some serious shortcomings with the "older" languages like C++ and Java. Which is why I'm so happy using TypeScript. It gives you the ability to layer static types on a language that still offers the flexibility and concise code that are unavailable in C++ and Java.
Unfortunately the original spec is long gone, but [1] at least mentions the gist:
--
As a side point, I hope switch statements are less like C and more like Rust (Rust happens to have better looking syntax, not just because its Rust):
match <identifier> {
<val> => {
//
}
..
}
C-style always creates confusion on how to indent blocks following case statementsWhat the GP poster was talking about was parentheses around the /conditions/ of an if statement.
Note that Rust (for example) doesn't require the latter.
In fact, if you always require braces (as in the post that you linked), then it's very easy to parse and read code which is lacking those parentheses on the condition.
i.e. `if (condition) x = x + 1` would be hard to read without parens. but `if condition { x = x + 1 }` (with mandatory braces) is quite clear.
Given the context, I'm pretty sure the OP was using the 'parenthesis' meaning.
Where is it otherwise? Is bracket={} a USism? I've never been sufficiently aware to isolate the demographic.
if foo*bar baz()
...being parseable as either of these: if (foo) { *bar } baz()
if (foo*bar) { baz() }
That example can be solved with enough lookahead but I think I found cases where it couldn't be (although I can't bring them to mind). Terminator tokens are another way to solve it, so you get Ada-style: if foo*bar then baz() endif
...or Go-style: if foo*bar { baz() } if foo
*bar
baz()
if foo*bar
baz()And even if you make newlines meaningful you only trade one pain for another, namely, you now need some kind of line continuation construct and lots of special cases where newlines are allowed...
In short: it's not that simple.
I see what the goals of Gravity are, but are there any reasons I want to use it?
Side note: not a huge fan of implicit self, i.e. class methods automatically referring to "y" as the instance variable "y". I realize c# and Java do it, but worrying about name elision at all is something I'm not a fan of. From an ergonomics perspective, it makes editor autocomplete features slightly worse, as a prefixed "this" or what have you can give it additional context vs "anything in scope"
It basically looks a lot like a subset of Swift designed to allow someone familiar with Swift to get going faster with Creo. Creo looks interesting mainly as a better integrated development experience than XCode provides.
Assume there exists a (pure) function `f` and a list `xs`. Does the following expression always return `true`, or, at least, never return `false`?
map(f, xs) == map(f, xs) λ> map acos [2] == map acos [2]
False :: Bool
Interesting. > map Math.acos [2.0] = map Math.acos [2.0];
poly: : error: Type error in function application.
Function: = : ''a * ''a -> bool
Argument: (map Math.acos [2.0], map Math.acos [2.0]) :
real list * real list
Reason: Can't unify ''a to real list (Requires equality type)
Found near map Math.acos [2.0] = map Math.acos [2.0]
Static ErrorsThis statement is true in any language. So it's useless as a criterium for determining which language is "functional" and which isn't.
Edit: except, of course, Haskell - `xs` could be infinite, in which case the expression wouldn't be true (but bottom instead).
lolcathost% js17
js> function twice(x) { return 2*x; }
js> var xs = [1,2,3];
js> var ys = xs.map(twice);
js> var zs = xs.map(twice);
js> ys == zs
false
js>
Of course, the fundamental problem (in both Haskell and dynamic object-oriented languages) is types:(0) Haskell doesn't have a type of lists. It has a type of potentially infinite streams.
(1) Dynamic object-oriented languages don't have a type of lists. They have a (dynamic) type of objects with physical identity, whose state (mutable or otherwise) can be interpreted as a list.
ML is free of these problems. It has a bona fide type of lists. Of course, you can also define a bona fide type of streams if you want to. Or a type of dynamic objects with identity. And those will be different types.
xs = [1,2,3]
ys = [1,2,3]
# are xs and ys equal?
ys.append(4)
print(xs == ys)
# no!There is no builtin object content equality binary operator in Javascript, at least as of ES5.
https://msdn.microsoft.com/en-us/library/ms173114.aspx
https://docs.oracle.com/javase/tutorial/java/javaOO/methods....
Unless the goal is to be overly pedantic and claim "method" is the term vs "class method".
Take a look at the Vector example. "y" in the constructor and other methods refers to instance variable y on the Vector class instance.
That's not me being overly pedantic, that's you misusing standard terminology. The term "class method" has a specific meaning that's quite distinct from "instance method" - the thing you're actually talking about. In fact, if you go to the docs of the very language this post is about:
https://marcobambini.github.io/gravity/classes.html
You'll find verbiage about 'class methods', again, as distinct from 'methods'. I can't think of an OO language or context in which 'class method' to just mean 'instance method' would make any sense.
It would seem that you were talking about what most people would call instance methods, or commonly just "methods" (unless you're in a language like Ruby, where you don't have functions as a first class entity -- if you want "class methods" as they are called, you define a method on the target class object's meta-class.)
class Foo {
private Integer bar = 0;
public Integer baz() {
Integer inc = 2;
bar += inc;
return bar;
}
}
Where `bar` is referred to in the same way a local variable is, even though it's actually a property of the class the method is defined on. It's equivalent to using `this.bar` but the compiler accepts it anyway.Each operation in baz() consists of Integer.intValue() and Integer.valueOf(int), like
Integer inc = Integer.valueOf(2);
bar = Integer.valueOf(bar.intValue() + inc.intValue())
...
besides dealing with unneeded indirection values outside [-128 : 127] actually create an object that has to be allocated+GC'd each assignment.
Such nuances give Java the bad rap. 'int' maps straight to the hardware, java.lang.Integer - not so much.I have my pet annoyances, too, don't get me wrong. Just the other day, I saw someone in a coffee shop using 8-stop tabs and had to set them straight. They were in the middle of a conversation about food, but this is important.
> Gravity has been developed from scratch for the Creo project in order to offer an easy way to write portable code for the iOS and Android platforms.
If you "just" create another one, without any novel contribution to the "languages" domain, you are basically just creating noise.
Nobody will use your language and nobody will write about it.
So.. .what is the point?
It doesn't have to be anything, but I'm not going to buy a car (or invest time looking at a new programming language) if you don't even tell me what it is.
As others have noted, the design goals of the project make it sound like Lua would have worked quite well for them. They didn't pick Lua, so it suggests their project has some advantages over Lua. They don't need to justify their decision, but if it does have advantages over Lua, it would be interesting to know what they are. And even if it doesn't, it would be interesting to know why they made the decisions they did.
The point of asking questions is to find out the answers; it doesn't mean we're all prejudging them based on the assumption their answers are going to be terrible, or even that the answers might be terrible. It's okay to start a project just because you want to!
// constructor
func init (a, b, c) {
if (!a) a = 0;
if (!b) b = 0;
if (!c) c = 0;
x = a; y = b; z = c;
}
Like func init (a=0, b=0, c=0) {
x = a; y = b; z = c;
}Nice touch to be able to do
func + (v) { ... } function init(a,b,c)
local x = a or 0
local y = b or 0
local z = c or 0
end
"and" and "or" short circuit evaluation in Lua; nil and false are false, everything else (including 0) is considered true.Here's the main use case: http://creolabs.com/gravity
I'm curious how well that works - I know that used to be fairly common in the '80s and '90s, but it feels like that hasn't been happening much of late. The only very similar examples I can think of are Swift and Xamarin; Swift had the advantage of a large customer base (everyone writing iOS apps), and Xamarin was based on an existing, well-established language (C#). And all the older big examples that come to mind, VB, Delphi, Objective-C, etc., were variants of an existing language (Basic, Pascal, C, respectively), not a brand new language.
Creo folks, are you finding that customers / potential customers are excited about picking up the new language? I'd love to live in a world where there's more work on programming languages (clearly, none of our existing languages are optimal) but I'm not super optimistic.
But I have the same question as yours. Why not just leverage Lua. I wish they made it clear what they're gaining. Maybe the end bundle size is smaller than Lua?
I think there is still a niche for something like a Lua/Erlang hybrid where there is a real possibility that the VM will run high level code units on multiple cores.
The other thing missing from Lua and LuaJIT which would be nice in future VMs would be support for SIMD vector optimizations.
I mean, creating an unnecessary programming language isn't strange — it's extremely common, and some are even good. But providing a rationale for creating the language that doesn't explain why you created the language is a bit odd, isn't it?
But the example doesn't show any Swift-like syntax... except for `func`. Other than that, this is a dead ringer for Javascript.
Edit: What's downvote worthy of this comment?
// b represents a range with values 1,2 var b = 1..<3;
Ah! I wish they had gone for 1..3 and 1>..3 and 1..<3 and 1>..<3 to make it easy to understand. The above would map to [1,2,3], [2,3], [1,2] and [2] respectively.
Range operator quirks with ... and .. have to today be memorized and waste developer seconds that add up to man-years.
Unfortunately, the reverse isn't covered yet (calling Gravity functions from C).
One good technique for spreading irrationality virally is to ask leading questions which continue the "debate" about something that really isn't that important. We have programming languages, they are often times hard to learn, and learning new ones, or making new ones, is something only a subset of the programming aggregate can and are willing to do. i.e. It's an important topic for a few, but for the rest of humanity, it really doesn't matter that much day to day. (Which is not to say a new language might eventually be useful to all, but that argument itself is irrational given it may occur in the future.)
I'm only calling out this argument here because I find this general viral behavior is occurring around other concepts in a way that is creating inefficiencies in communication channels - something we didn't really intend when building the Internet.
I agree with you. This isn't something that needs a big discussion. "Do we have too many languages? Should we cut some of them?"
But I think the common response of "oh god, here we go again" is unproductive and, frankly, stupid. It reflects something about the community. I'm not asking you to use my toy language to build the Next Greatest Enterprise Application (TM). I just made something cool, and maybe you can use it to make something cool too.
The FIRST thing I do when checking out these new language announcements is search for something, anything, that shows this language is different than all the others.
My next concerns are wondering if the language will... 1) Make it to 1.0 release 2) Have thorough documentation 3) Have much of a community 4) Have tooling that makes it easy to use 5) Survive long enough to make a viable long-term investment to learn and to use.
Edit: I also am concerned if this new language makes the same mistakes as previous languages. For example, I consider allowing null as a mistake. Null is familiar, it's easy to implement, and it causes untold grief.
The language is dynamically typed. null is only questionable in statically typed languages. There's no benefit to a Maybe type in a dynamically typed language.
looks like gravity an mit-licensed open source offering.
It definitely beats the standards of my (unsubmitted) hobby projects: 1) Logo 2) Getting started guide 3) Other books
On the other hand, it loses as a hobby project posting. Indeed the effort I think should go into such a posting is the reason why my hobby stuff isn't posted. Such posts are good when they document that something significant can be achieved "out of the gate" (C4 or scheme48 or something-amazing-in-500-lines) or if they document the steps to reach a more-mature-than-expected state.
There should be more hobby languages and more hobby transactional RDBMSs and more hobby ANYTHING we take for granted.
If someone writes up "docker in bash" as an example from about a year back, or something similar, whether it is a hobby thing or in "experimental production", it stands or falls not on what is achieved but what we the community get from knowing that they achieved it.
Apart from this boring grumbling, the project is very interesting. Waiting for internals (https://marcobambini.github.io/gravity/internals/index.html) to arrive.
All serialisation frameworks I've seen map internal record types (structs, objects) to an external schema, and write directly to record fields -- breaking down that "gate". What I would like is to map those schema to something like a constructor/factory parameter list instead. (Python keyword arguments come close, but the lack of typing means there is still no schema).
Serialisation libraries should confine themselves to converting between (typed) key-value pairs and wire formats. Then there should be syntactic sugar to help the transition between that plain-old data and the real domain model.