The Wake Programming Language
wakelang.com
wakelang.com
But what I really like is the presentation: I like how all features are summarized, pointing out what is novel, and then everything is just discussed using examples and comparisons to other languages. This is something I'll have to try when I finally get my own language off the ground :).
I wonder if the author is interested in engaging with researchy PL designers. E.g. the testability orientation of the language would make for a good Onward paper, or maybe a Future of Programming workshop presentation.
I haven't written a technical paper before, but tried to make one on the testability here: https://docs.google.com/document/d/1hT761Cl2-r7cSJV4zR69PGAD...
(I really like Rust's take on this with the semicolons—just leave off the semicolon to return—it makes the semicolon actually useful.)
fn foo(x: bool) -> i32 {
if x {
1 // no semicolon on the 1
}
let a = 2 + 3;
return a * 4;
}
It's not implicitly returning the 1 from `foo`. An early return would need to be written `if x { return 1 }`. On the other hand, the `return a * 4;` could just be written `a * 4` since it's at the end of the function.This rule means the scanning required is just looking at the end of the function.
In any case, having a static type system means I have never personally encountered a bug caused by this sort of implicit return in Rust.
Maybe I'll add a 'noreturn' keyword; single expresions are automatically returned, and you can use a 'noreturn' statement to explicitly return void despite running a non-void expression.
Something I've played with in languages I've worked on is named returns [1], which I like for that case.
[1] https://github.com/stormbrew/channel9/blob/master/sample/c9s... -- see the get function definition, '-> return' names the return 'channel' and 'return <- val' calls it (which returns). Now I might consider having an implicit '<- val' with no lhs that calls the current function's return, I think.
I do think a special case for single statements makes sense, though.
Why aren't declaration statements in Rust just expressions that evaluate to the value being bound to the name being declared?
Would this mess up Rust's type checker somehow?
If it's not the norm, I'd rather have an explicit "nil" or something at the end.
Also, because function signatures are never infered in Rust, mistakenly adding or forgetting the last semicolon will always result in a type error.
The most common pattern in my Rust code is:
`statement; statement; expression` where the expression is what I actually want to return from this function
it seems more noisy to say `statement; statement; return expression;`
function RecordValidator(sessionHolder) {
function validateRecords(records) {
return records.every(validate);
}
function validateRecord(record) {
if (record.lastRevision !== undefined
&& record.lastRevision.user !== undefined) {
return record.lastRevision.user.getAccounts().every(function(account) {
return sessionHolder.hasAccount(account);
});
}
return record.revisions.map(usesLimits);
}
function usesLimits(revision) {
return sessionHolder.hasUser(revision.user);
}
return {
validateRecords: validateRecords,
validateRecord: validateRecord,
usesLimits: usesLimits,
};
}
The language looks like it has much to like.> setIdThenSave(newid Num, Bool recursively) { ... }
i like the idea of letting a type do double duty as a variable name if it's obvious in context, and being aliased by an explicit name if wanted/needed, but letting the order be irrelevant sounds like unnecessary flexibility to me - it makes writing no easier, and reading harder.
Of course, I do see where the complaints come from, and a part of me fears the day that someone releases a wake linter which requires aliases to follow the type. If that were to happen I think I'd nix the idea in favor of unity in the community.
that(expected Bool, expected Int)Equals(actual Bool, actual Int)
to match on two values, for instance. on the other hand, constraining the adjective to come before the noun is an english-based convention, so you're probably right about seeing which way the community leans before doing anything.
return Record[].any({
r -> return !validate(r);
});
shouldn't this be return Record[].all({
r -> return validate(r);
});
?And the inequality seems to be strict in Wake's case but weak in Java's. Finally, Java won't always return from `validate`.
The Java would really benefit from the newest version. I'm no Java expert, but I think it would look a bit like:
public class RecordValidator {
public RecordValidator(SessionHolder mySessionHolder) {
sessionHolder = mySessionHolder;
}
protected SessionHolder sessionHolder;
public boolean validate(List<Record> records) {
return records.stream().allMatch(this::validate);
}
public boolean validate(Record record) {
if(record.lastRevision != null && record.lastRevision.user != null) {
List<Account> accounts = record.lastRevision.user.getAccounts();
return accounts.stream().allMatch(sessionHolder::hasAccount);
}
record.revisions.stream().filter(this::usesLimits).count() < 3;
}
public boolean usesLimits(Revision revision) {
return sessionHolder.hasUser(revision.user);
}
}What ideas are new? I'm not sure about provisions because the examples aren't really clear, but all the other features I've seen in other languages before.
> 3. Shadowing (concise, safe)
It doesn't seem like shadowing is the feature here, rather the use of '$' to prevent shadowing.
> Lists (called Arrays in many other languages)
There's a very good reason for this. Lists and arrays are very different data structures. Why create confusion by calling them lists?
> Since Wake blurs the line between variables and types, we can boast the smallest foreach loop of any language.
Really, the smallest foreach loop of any language? Come on.
> Self Executing
Why is this called 'self executing'? Also, I'd expect any language with lambdas to support calling a lambda right after it's created.
Other discussion here: https://news.ycombinator.com/item?id=9040029
Yeah, I had posted that to Reddit, where it didn't do too well, but someone posted it here where (for some reason!) it did much better.
Figured in addition to the story of creating Wake, I'd post the home page so people could look into it more!
I've typically found PL related articles do much better on Hacker News than Reddit, I think perhaps because of differing (but overlapping) target audiences. Always found it interesting what articles work here but not on Reddit (the converse isn't as interesting...)
Same in the "What Wake did without" section. Yes, you do not have those features, or bugs, but have you really "FIXED" a bug? There is no bugs you have fixed, just different design decisions.
edit: The language may or may not be actually worth something, but those things make it look like they try to hard to me.
Extremely minor potential nitpick: correct me if I'm wrong, but I think this sentence implies that Javascript is not type-safe, when it is indeed type-safe; it's just dynamically typed, and its type system gives meaning to all expressions (where that meaning is to signal an error in some cases).
"But wait a minute, Assembly is not type safe!" But yes it is, just every type is a binary number. It's not Assembly's fault that you're trying to use binary numbers to print characters to the screen or point to regions of memory and somehow get the two mixed up.
https://www.destroyallsoftware.com/talks/wat
How about {} + [], is that deliberately zero, and why is addition not commutative in this case if it is allowed? Or {} + {}?
I think most people would infer type safety to mean that attempts to coerce types which are meaningless result in an error, not meaningless output, like the result of "string" - 1, or {} + "string" or {} + []. Otherwise your type system isn't going to stop you doing something insane by mistake, and is therefore not adding any safety.
{} + "string" or similar just shouldn't be allowed, and in most languages (let alone type safe ones), it is not.
Aggressive type coercion is not type safety. It does not prevent type errors. It just sweeps them under the rug.
5 - 'foo'
That's a type error. It's not a convenient shortcut for `NaN`. var a = 1;
a = "foo";
is not type safe.The reasons I switched away from LLVM are:
- the LLVM API is huge, not very well documented, and changes radically from version to version. - LLVM library consumers are not well supported by the project. Frequently what you get when install it is a set of static libraries, which take forever to link against and lead to 150MB binaries. - LLVM's supported architectures set isn't great yet. C provides a portable, vendor-neutral intermediate language which works everywhere and is easy to read and therefore debug. - targeting C makes library integration trivial (as your output program can use the library's own headers, which means ABI issues become nonexistent).
I did contemplate a partial switch, where my compiler didn't link against LLVM at all but instead just spat out LLVM bitcode assembly --- but emitting C was the same amount of work and so much more flexible. The only downsides is that C can't do tail calls, and getting the debug information to match up is more work, but that's about it.
(For the interested: Cowbel is an experiment at producing a minimal static duck-typed language --- all types are anonymous; you refer to objects only by their interfaces. The compiler than uses type inference to determine the actual concrete type of the object. This allows it to, e.g. use a single machine word to represent a number if you're never going to do dynamic dispatch on it, which means you don't end up with the weird schizophrenia of C++ and Java where some types are scalars and some are objects and they have different semantics.
It's also an attempt at minimalism; I wanted to remove as many features as possible and still end up with a expressive language with Javascript-ish syntax. I'm really proud of the way I managed to unify scope blocks and objects...
It works beautifully, and produces tight, fast code, but the compiler became unmaintainably complex and needs to be rewritten from scratch, which I haven't done yet.)
Can you please tell me which GC is that ?
I don't. Thanks to all those that do though. Interesting thought experiment, even as a spectator.