No, I use braces for the computer, and the computer automatically and unambiguously indents it for me.
If anything the wasted effort happens in whitespace significant languages like Haskell and Python where the computer can't tell what you want and you have to cycle through all sensible indentations (for every line!)
if z:
print 'a'
print 'b'The main problem with indent oriented languages is that not everyone is or wants to use a modern editor. Then there are LISPers who think braces everywhere are a swell idea.
Nonsense.
Try pasting a block of Python into Hacker News and you get something that starts off like this:
import os import random def do_something(x): if x: fd = os.open(x)
and only gets worse. A language with braces/semicolons has no such problem; it is easier to communicate with others, and the absolute value of being able to communicate with others when starting a new language is exceptional.
White space has significance for humans. The road to the Turing tarpit is paved with human intentions. Describing computation mathematically is a solved problem. Expressing it clearly for and by humans, not so much.
Haskell is particularly guilty of creating several different indenting possibilities, and does require constant intervention. Python is less bad, but still requires more effort than C for example.
https://github.com/djc/runa/blob/master/runac/parser.py#L54
(Runa uses tabs for indentation, not spaces, but it's basically the same thing.) Whitespace at the start of a line is a separate token, then I add a thin layer of processing that turns a change of indentation level (i.e. count chars in the token contents) into INDENT or DEDENT tokens.
What? My editor indents stuff for me as per PEP8. I don't have to think about it. Why do you?
def fun():
for x in xs:
if a:
b
c
There's no way for an editor to know where to re-indent c to. You have to cycle through the indents manually.Imagine a syntax aware editor which could display code from a language using the syntax or style of another. (This might only work from a single base language, there are too many "odd" features in languages which couldn't translate universally).
So, since I like python, it could be displayed PEP8 style. Someone else could see it with LISP braces everywhere. Another could have it with 2 spaces and 'end' keywords, or {curlybraced;} (in K&R style, or whatever you like).
For example, a typical C program (sequence of imperative statements) displayed with lisp syntax will look awful, yes, but so will a typical lisp program (deeply nested expressions) rendered with C syntax.
Getting rid of text doesn't change the fundamental issues: Languages would still have different semantics (and thus suit different/custom representations) and it wouldn't make any more sense to mix-and-match than it does now.
Diekmann and Tratt have a theory of Language Boxes[0][1] which provide the groundwork for achieving this kind of editing. They enable language quotation without the need for introducing per-language delimiters, the need to quote code in strings, and the need for escaping characters when hosting one language inside another. The editor is aware of where the language boundaries occur because they are specified by the programmer. The semantics of hosting one language in another are left up to the programmer to specify.
[0]:http://lukasdiekmann.com/pubs/diekmann_tratt__parsing_compos...
[1]:http://soft-dev.org/pubs/html/diekmann_tratt__eco_a_language...
That's why I kind of was trying to aim towards saying you /COULDN'T/ have a universal language syntax translator - but for a (new?) language, you could create (possibly) different interfaces to the central logic and structure of the code to suit different preferences.
Sort of how we have different skins and fonts and so on now.
http://en.wikipedia.org/wiki/APL_%28programming_language%29
It was very, very clever.
It was so clever hardly anyone understood it, and it's (mostly) forgotten.
Having said that - I kind of agree. It seems like most languages are attempts to:
1. Create a human-readable text-based representation of symbolic logic.
2. Chunk the symbolic logic in (hopefully) useful ways.
3. Cross-correlate symbolic levels, so at one extreme you have actual bytes in physical memory, at the other you have arbitrarily complex symbolic data structures.
4. Build simple error checking into the language so it's impossible to write obvious nonsense. (This includes, but isn't limited to, all type systems.)
5. Constrain the operations that are possible for similar reasons. ('State' etc.)
This is all more or less taken for granted. I'm not sure it should be. Basically it's a bottom-up approach to language design - reduce operations to binary algebra, add constraints.
But top-down languages like Prolog and (kind of...) Erlang try to do interesting, powerful, things, and have at least a few features that Just Work.
So I think the top-down approach is underexplored. There's a sweet spot between top-down simplicity, expressiveness with minimal cognitive load, and processing efficiency.
It's unlikely current syntax conventions are close to it.
I think most people know that languages are different points on various trade-off scales, so there will never be one single best language.
But more variety might not be a bad thing.
APL is absolutely nothing like the parent described.
http://www.jsoftware.com/papers/tot.htm
Three decades after first conception, Iverson developed the language J using only ASCII characters and based on what he learned over roughly two decades of APL's deployment in the field. IMO, J is worth looking at because it may change the way a person looks at programming languages and their design.
I do not understand all the constant discourse about languages. Personally I prefer to choose something simple and small, and stick to it. To increase convenience when working with these terse languages, I write code generators.
To me, it is not the language that matters (except as below), it is the programs that the author chooses to write and how those programs perform.
It is probably my own selective bias but I find that the smaller programs written in relatively terse languages tend to be of higher quality. When I see a verbose language used to write a program, I am reluctant to use the program. But I would never suggest that someone else make the same decisions. I believe one should think for herself.
There is not so much discussion about the terse languages I use. I am inclined to think this is a good thing. Then I can focus on the choice of the programs the author chooses to write instead of her choice of language.
There's a pretty exhausting amount of work to get to the same toolset we have for text-based languages though.
* Optional typing (like PHP7/Hack/ES7)
* support for compilation (statically linked native
binaries) and JIT (like Visual Basic 6 with its P-Code)
* memory safety (no null/dangling pointers like Rust)
* procedural & object oriented & functional style
(like JavaScript/PHP/C++)
* modern base standard library / API (like
C/Go/JavaScript/PHP but more modern with better naming,
not as heavy as Java class libraries or .Net Framework)
* third party libraries (like Nodejs NPM)
* online documentation with code samples and
community comments (like PHP.net)
* good debugger
* IDE plugins for IDEA/Eclipse/VS
* good OS support (32 & 64bit) for:
Windows & OSX & Linux & BSD & iOS & Android.
Edit: * Actor model (like Erlang)
* Built-in concurrency primitives:
° light-weight processes (like Fibers in WinAPI,
Coroutine in Lua, Goroutine in Go),
° Channels (interprocess communication and
synchronization via message passing like in Go
and OCaml)* Optional types
* The VM compiles source into machine code on the fly, or you can embed the VM into your app.
* No pointers.
* Core library is full-featured (https://api.dartlang.org/apidocs/channels/stable/dartdoc-vie...)
* Third-party libs and packages in https://pub.dartlang.org
* Docs at api.dartlang.org and www.dartdocs.org
* Debugger works in Eclipse, IntelliJ, WebStorm
* Works in Win, Mac, Linux, 32 and 64 bit.
* Also runs on ARM and MIPs
* Isolates for memory-safe concurrency
* Async primitives like Future, Stream, and async/await
(disclaimer: I'm a PM on the Dart team)
I don't however think that's what was desired.
Hadn't it boast itself as a C++ replacement(which pissed off the C++ community=bad rap), I think it would have been a very good candidate. D minus all the unsafe features looks better than Go, IMHO. Go lack of expressiveness forces developers into copy/paste mode.
C/C++/Object-C/PHP have short functions with names like strlen, strstr, etc. Java/C#/JavaScript have .length() and things like System.out.println()/Console.Write(). Ideally, I would like a middle ground. The Java/C# standard library is too verbose and the C standard functions are a bit cryptic.
It's great one can use different programming styles in JavaScript/PHP/C++. In PHP many functions are available in procedural and object oriented style, e.g. http://php.net/manual/en/mysqli.query.php
As the author mentioned, a machine can look at how the arguments are used and make some educated guesses. The big problem is that humans have to do the same.
That's why I like optional types à la Dart. Not only do they help with static analysis, they also act as documentation.
With a good editor, this documentation is right at your fingertips. When you type a function's name, a call-tip will remind you of the expected arguments. If you've added type annotations, the types will be there, too.
Why? Just get the machine to do it.
It's like when you see programmers doing arithmetic in their heads. "You're sitting in front of a glorified calculator!"
I meant the writing stage, not the checking stage.
Imagine you don't know which type to pass. So, you'd have to pass something (null or whatever) in order to generate an error which gives you a clue.
That doesn't sound very convenient.
Well, the machine could check which types match that fingerprint, which might work okayish if the list isn't too long, but it won't tell you anything about the writer's intend.
Is a list of doubles, a list of ints, a Float32x4List, or a Float64x2List really the same thing?
What if it's actually meant to be used with something else which also supports the [] operator and whose items support the + operator.
Static analysis might not be able to tell you because it doesn't know all packages in existence. That package might not have been referenced, because that's not required to use a type from that package.
How does the generated documentation look like? It takes one argument "foo" which is something which has a "bar" field and a "baz" method? I'd rather have a concrete type there. "int x". Done.
What if you optimize the function a bit and now the fingerprint doesn't match one or more types anymore. Was this a breaking change?
Your intention didn't change. You always had one particular type in mind.
Exactly. Many people already use IDEs, or programs which provide auto-completion or hinting of the types a function accepts when writing out a function name - the type does not need to be explicitly written for the machine to identify the type of the function.
At the company where I work, most engineers have real, actual calculators on their desks. I think I even saw a slide rule once. So they sit there, sometimes, doing arithmetic on their calculators and then type the results into an Excel spreadsheet.
Without type annotations, the types will be there too for a language with type inference. The editor just has to ask the language implementation "hey, what is the type for this function?" and show the result back to the programmer.
That's some comical post rationalization.
The reason why len is a function is because it was in Python before Python started receiving OO features.
As a result, Python is a crazy hodge podge of imperative, OO and functional semantics where you never know if you should be calling `o.foo()` or `foo(o)` unless you've been writing Python since the late 90s.
"In February 1991, Van Rossum published the code (labeled version 0.9.0) to alt.sources. Already present at this stage in development were classes with inheritance, exception handling, functions [...]"
let v = &vec![1u32,2,3];
println!("{}", v.len());
println!("{}", Vec::len(v));Successful languages start with a clear idea of what problem they want to solve, creating coherency at a high level. Values are ranked and might be nice is distinguished from what is held dear. The starting point is identifiable and the passion positive. Saying "the ending point is not here," isn't enough.
Brain-dumps are valuable for discussion and as a first step. From there, we just need to follow our normal programming routines: Write, refactor, test, repeat.
There's a clear goal when writing a language that is both a floor wax and a desert topping. On the other hand, all writing a language with the goal of being neither floor wax nor desert topping just gets us a floor topping and a dessert wax. There's no problem solved. Griping isn't brainstorming.
Brainstorming is structured. Productive brainstorming is constrained by reality. By which I mean that brainstorming about something like type inference acknowledges that type inference is subject to the Halting problem and that dynamic typing as in Python does not entail type inference.
Starting with Assembly, all higher level programming languages are DSL's over machine code. Things I hate is not a domain that leads to insight or a coherent minimum language. Python's core was addressing pedagogical problems such as beginners learning to format code well. Google's Closure compiler addresses the problem of JavaScript performance. Rust is intended to address client server programming. For each there is something that can be measured objectively and improved.
Don't misunderstand me, there's nothing wrong with writing a programming language as a learning exercise or to scratch one's own itch or solve the world's problems. But it is an engineering design exercise not a poem. The facts of computation make it so.
It's no good looking at problems that other people have solved (or proven that they can't be), when we could be looking at new ways to approach problems instead. For example, we'd know that "statically inferred duck typing" is already well researched. It's called structural typing.
With technology coming more and more into our lives, such that our lives will depend upon it behaving as was intended, we're really going to reach a point where we've got to say enough is enough. The languages (and approaches to development) we're using are not fit for purpose anymore.
It'd be worth taking a look at things like its macros as well – I actually think Julia hits on a lot of the points in this post really well, though of course no language is perfect.
[0] http://docs.julialang.org/en/latest/manual/types/ [1] https://github.com/astrieanna/TypeCheck.jl
Minor nitpick:
> Tut, tut. That should really be a set! It’s much faster, O(1).
Structures like sets have a lower complexity but higher constants (i.e. the overhead of hashing the value etc). When you have a small number of values, a straight linear search over an array will often be faster (which is why it's useful to have the explicit choice).
> I seem to have a knack for trying to write things in Rust that rely on intertangled references and mutability: first a game, then a UI library…
First of all, a UI library is EXACTLY the kind of thing I want you running through Rust and having a long, drawn out fight over mutability. Every UI we currently have absolutely sucks in a multi-threaded context. I want the compiler to make you think long and hard that maybe, just maybe your ideas about how to architect a GUI library are very broken and that you have to restart from a clean slate.
As for a game, do you really have that much mutable state, or are you just conditioned to use mutable state by default? Games do have lots of mutable state, but games also have lots of bugs due to multi-threading that being forced to analyze mutable state exposes.
- too Rust/Python focused - the author needs more rounding of PL experience. I would suggest spending some more time with Haskell/ML and then some time with Common Lisp/Scheme. Reread the Programing Languages survey textbooks from college.
- not really enough familiarity with the theoretical side of PL. A metric ton of work has been done in academia, some of the listed problems have been solved, and at the worst, will give the author a nice way to go to sleep at night. This kind of relates to the previous point.
The concept of Locality I think is an important one and a real take-away from this essay. You want to be able to ensure that your code is meaningful locally without bouncing around half a dozen modules and inheritance trees just for basic understanding.