
Frame-Based Editing [pdf] - panic
https://kclpure.kcl.ac.uk/portal/files/71018111/Frame_based_editing.pdf
======
kot-behemoth
There is an app called Lisping which allows writing a variety of Lisps (Scheme
and Clojure) on iPads. The great thing about it was that there was minimal
typing - the interface made the AST very clickable, with minimal cursor
movement. When I tried it, it was such a great way to edit code on an iPad.
Demo video:
[https://www.youtube.com/watch?v=nHh00VPT7L4](https://www.youtube.com/watch?v=nHh00VPT7L4)

~~~
nocman
Wow, I watched the whole video and all I can say is -- huh?

That looked totally painful, and not at all fun. Granted, much of this is due
to the fact that it's a touch interface, but I'm not seeing it as very useful.

I'm a huge Lisp/Scheme/Clojure fan, but I didn't find this at all impressive.

~~~
aaron-lebo
Yeah, it's really hard to see the utility in that.

That literally takes 10x longer to enter anything than it does in a decent
editor. I imagine some vim and emacs wizards can edit even faster than that.

Dumb snark incoming but it's like using a hammer to chop wood.

------
hcs
Coincidentally I just started working on an editor for touch screens that
relies on displaying nesting like this. I also worked on a syntactic zoom
which I'm sort of proud of, but don't know how practical it could be yet.

Editing is still in progress but I have a read-only demo at
[https://gashlin.net/tests/ecola/hn/](https://gashlin.net/tests/ecola/hn/)

~~~
binhqx
On a ms surface running chrome 59, that pinch zoom feels nice

------
auggierose
The core thesis of this work is "that text is an inappropriate way to model
structured program code". I think that is wrong, text is a great way to model
structured program code.

That doesn't mean that the ways we use text these days for programming
couldn't be improved and augmented. For example, the example in Figure 3 is
very pretty and readable. But there is no reason why this couldn't be what you
see when still editing everything as text. Basically, it could be a more
advanced form of syntax highlighting. The reason why this is
difficult/impossible to achieve with Java is because of Java's syntax.

Therefore I think when approaching programming from a user interface point of
view, it is crucial to also work on a better syntax for the programming
language itself. Ideally, work like described in this paper should go hand in
hand with work to develop better syntaxes.

~~~
falcolas
IMO, the big problem with text as a representation of (imperative) code is
that it only represents the program's execution flow; the visualization of the
flow of data must be done in a person's mental model. The side effect of this
is that a programmer must build the proper mental model anytime they want to
make a change, or they risk mucking up the data. Object orientated programming
was an attempt at localizing data changes, at the cost of complicating the
overall flow of the program's execution.

Representing the flow of data and not the program is one advantage that many
functional languages have, at the cost of removing the visualization of the
program's flow. Often this doesn't matter, but sometimes it does. When it does
matter, you're faced with the same challenge for the programmer.

So ultimately, even the best syntax can only help you model one thing - either
the flow of the data or the flow of the program - and the other flow must be
modeled internally. It would be cool if both could be visualized by our
tooling simultaneously.

------
escherize
Yeah, it's a pretty good idea. I've been using lisp and expand-region[1] and
it just makes this frame-based editing dream come alive.

I've just recorded a video where I'll refactor some code for fun. This code
adds two arrays one has strings in it like ["1" "2" "3"] the other has numbers
like [1 2 3].

Video: [https://s3.us-
east-2.amazonaws.com/photoblobs/2017-06-22_003...](https://s3.us-
east-2.amazonaws.com/photoblobs/2017-06-22_003949.mp4)

I do have a couple typos / mis-compiles but that's sort of par for the course.
Hope you enjoy!

[1] - [https://github.com/magnars/expand-
region.el](https://github.com/magnars/expand-region.el)

~~~
Huege
Exactly

------
broxp
Regarding coloring, I created a simple Ruby editor with syntax highlighting
that features...

\- Indentation based coloring of whitespace

\- Nesting-based coloring of parentheses

You can try it out here:

[https://broxp.github.io/ruby-ide](https://broxp.github.io/ruby-ide)

Of course, these ideas are not new.

There are plugins for IDEs for some languages, one that I recall is the F#
depth colorizer:

[https://cyanbyfuchsia.wordpress.com/2013/11/18/cool-
visual-s...](https://cyanbyfuchsia.wordpress.com/2013/11/18/cool-visual-
studio-extensions-for-f-developer/)

And there is parentheses highlighting in Eclipse (when touched by the cursor).

------
brad0
Is this essentially wrapping each scoped segment of code into a "frame" for
manupulation using a mouse?

I must be misunderstanding, how can this be more useful than plain text?
Eliminating syntax errors?

~~~
Jtsummers
Not just with a mouse. The frames can be detected automatically. Imagine a
typical IDE where:

    
    
      while (...) {
    

Automatically inserted the next `}` and moved the cursor between it. But in
the frame based editor, the `{` and `}` are elided from the presentation,
replaced with a colored block or frame around the inner kernel of the while
loop.

    
    
      +++ while (condition)
      +   --- if (condition)
      +   -   *** actions
      +   ------------------
      ++++++++++++++++++++++
    

Scratch (the example in Figure 1) is definitely a mouse driven interface, but
beyond that and its visual presentation, it's more a cousin to the frame based
model than a precise representation.

It gives you a better (arguable?), structural way to view code, and to edit it
with both text input and mouse.

~~~
a3n
Yes, it's arguable. :)

(curmudgeon)A well-formed program is "defined" as what the compiler expects.
Like literate programming, this hides from me what's being presented to the
compiler, and sets me adrift from what the program actually is.(/curmudgeon)

It also reminds me vaguely of writing with Framemaker.

~~~
edmccard
>this hides from me what's being presented to the compiler

Isn't that the whole point of abstractions? Like, when you write a function
call, you see "foo()" but the compiler sees all the individual instructions in
the function. The same with macros, templates, etc.

And on a purely visual level, the example 'jtsummers gave just seems to be an
extension of code folding and other tools that let you focus on one part of
the code while ignoring another.

~~~
TeMPOraL
The essence of programming is being capable of constantly walking up and down
the abstraction ladder. Trying to hide behind a perfect abstraction is as
problematic as the belief that abstractions are evil because they're too
complicated.

Abstractions are transient. You want to use them when they help you, but it's
good to be able to step down and verify what's going on.

~~~
edmccard
>The essence of programming is being capable of constantly walking up and down
the abstraction ladder ... it's good to be able to step down and verify what's
going on.

Good, yes, desirable, often, but I wouldn't call it "essential" to the art of
programming.

I once worked for a company whose data was managed by a COBOL application on a
mainframe a couple hundred miles away; there was no walking down that
abstraction ladder (without shelling out a five-figure support fee), so our
in-house IT department had to take advantage of the fact that the 3270
terminal emulator we used to access the mainframe, could be driven through a
COM interface.

I'm sure there are lots of other examples of jobs that don't have the luxury
of being able to step down and verify lower-level code, and I wouldn't
characterize them as missing out on some "essential" aspect of programming.

------
speps
Reminds me of Construct :
[https://static2.scirra.net/images/fresh/c2/gallery/fullsize/...](https://static2.scirra.net/images/fresh/c2/gallery/fullsize/jpg/eventsheet-
edit-01.jpg)

~~~
broxp
Or programming in the RPG Maker:

[http://d289qh4hsbjjw7.cloudfront.net/rpgmaker-20130522223546...](http://d289qh4hsbjjw7.cloudfront.net/rpgmaker-20130522223546811/files/screenshot-
rpg-maker-vx-13.jpg)

------
gr__or
I wrote a similar post, though much shorter and less detailed. Nevertheless
eerily similar: [https://medium.com/@grgtwt/code-is-not-just-
text-1082981ae27...](https://medium.com/@grgtwt/code-is-not-just-
text-1082981ae27f)

Greenfoot really was the biggest inspiration, but I'd really like to build
something more general purporse. Aka pass in a grammar file and then you can
use the editor for that language.

------
sillysaurus3
This is pretty incredible work wrapped in an unassuming name. It basically
presents an entirely new way to interact with any programming language. You
could make an emacs mode that worked this way, for example.

I could see this being one of the fundamental ways of overcoming Lisp bias.
Lisp still isn't mainstream. Clojure was a nice attempt, but it fell short.
You can find companies that use Clojure, but it's not the lingua franca of any
domain (except perhaps text editors).

If you were to expose a way to write Lisp without dealing with any parens at
all, it might have a chance of sparking the interest of younger programers
long enough to seduce them to Lisp's other benefits: when you write in Lisp,
you're writing in the abstract syntax tree normally generated by other
languages. This allows you to write macros, which transform the tree in
arbitrary ways. It's trivial to write a program to analyze your entire
codebase in arbitrary ways (what are the most popular function calls? what's
my dependency graph look like? which functions are unreferenced?) which is
normally a herculean effort in other languages.

And it all comes down to syntax. `(if a (b) (or c d))` is so utterly _foreign_
to most programmers compared to `if (a) { return b(); } else { return c || d;
}` that it's nearly impossible to overcome the inertia long enough to persuade
them that the tradeoff in readability is worth the power you get.

I think this work could be helpful here. When you throw a newcomer in front of
a Lisp editor and say "Write a program," what goes through their minds? "How
do I write an if statement?" "How do I call a function?" "How do I set a
variable?" "How do I loop while a condition is true?" All of these are
abstract concepts, not specific to any language, let alone Lisp. That'd let
them avoid dealing with parens altogether. Then you can introduce the idea of
a macro, which just combines new ways of using existing concepts.

Regarding color: I've often wished for colored quasiquotation. `(foo `(bar
`(,baz))) would be more useful if your editor displayed the background color
differently for each level of quasiquation. It would also de-mystify
statements like (fn (x) `(define-macro foo (y) `(define ,y ,',x))) which can
otherwise be incredibly difficult to reason about. (Thankfully nested
quasiquotation is rare, but suffice to say I wish editors used color more
effectively rather than stylistically.)

Sadly, emacs is one of the only editors flexible enough to implement the
concepts presented in this paper, and the intersection between emacs users and
novice programmers is about as large as the intersection between hackers and
MBAs. But you can flip it around: emacs _is_ flexible enough. That means you
can ship a custom preconfigured emacs designed specifically for Lisp hacking,
set up to mimic Atom/Coda/Sublime/whatever.

~~~
Retra
I keep hearing this kind of talk about lisp. I've never actually written
anything in it, but if you asked me why, it would have nothing to do with
parens or syntax. It has everything to do with the fact that, for most
purposes, Python suits me just fine, and for almost all other purposes, I want
a language that compiles to machine code.

Lisps just don't bring much to the table. Their dynamic-ness brings overhead
that is not justified _unless_ you're doing crazy macro stuff, and ad-hoc
crazy macro stuff is not easy to put into code without hurting readability and
comprehension.

~~~
omaranto
Plenty of implementations of dialects of Lisp have compilers that produce
machine code. I would even say that for Common Lisp implementations it is more
common to have a compiler than to not have one. There are several great Scheme
compilers too, and Racket has a JIT.

Here's a sample session with SBCL, where I define a function, which is
immediately compiled, and then I request a disassembly:

    
    
        CL-USER> (defun foo (n m) (* (1+ m) n))
        FOO
        CL-USER> (disassemble #'foo)
        ; disassembly for FOO
        ; Size: 48 bytes. Origin: #x1007CED6F3
        ; 6F3:       498B4C2460       MOV RCX, [R12+96]               ; thread.binding-stack-pointer
                                                                      ; no-arg-parsing entry point
        ; 6F8:       48894DF8         MOV [RBP-8], RCX
        ; 6FC:       488B55E8         MOV RDX, [RBP-24]
        ; 700:       BF02000000       MOV EDI, 2
        ; 705:       41BBC0010020     MOV R11D, 536871360             ; GENERIC-+
        ; 70B:       41FFD3           CALL R11
        ; 70E:       488B7DF0         MOV RDI, [RBP-16]
        ; 712:       41BBA0020020     MOV R11D, 536871584             ; GENERIC-*
        ; 718:       41FFD3           CALL R11
        ; 71B:       488BE5           MOV RSP, RBP
        ; 71E:       F8               CLC
        ; 71F:       5D               POP RBP
        ; 720:       C3               RET
        ; 721:       CC10             BREAK 16                        ; Invalid argument count trap

~~~
white-flame
And if you declare types in SBCL as fixnum (register-sized ints):

    
    
      CL-USER> (disassemble #'foo)
      ; disassembly for FOO
      ; Size: 19 bytes. Origin: #x100784BCCB
      ; CB:       48FFC0           INC RAX                          ; no-arg-parsing entry point
      ; CE:       480FAFC1         IMUL RAX, RCX
      ; D2:       48D1E0           SHL RAX, 1
      ; D5:       488BD0           MOV RDX, RAX
      ; D8:       488BE5           MOV RSP, RBP
      ; DB:       F8               CLC
      ; DC:       5D               POP RBP
      ; DD:       C3               RET
    

As far as overhead goes, the SHL makes room for tag bits (and notice that's
only done once, not per math op), and CLC indicates that the function doesn't
return multiple values. That is not significant overhead, and will absolutely
destroy reference Python in speed.

~~~
omaranto
Maybe it's worth pointing out that to get that code like that from SBCL it's
not enough to declare that m and n are fixnums, you also need to promise the
compiler that the multiplication won't overflow:

    
    
        (defun foo (n m)
          (declare (type fixnum m n) (optimize (safety 0)))
          (the fixnum (* (1+ m) n)))

~~~
white-flame
The reason I didn't list it is because there's so many different ways to do
it.

The optimization declaration can be made globally, or per-file; declaring the
type of the foo function (including parameters & return values) externally
will fully cover this function without having anything additional in the body;
there's helper macros to explicitly manage static types, etc.

So the type declarations don't need to be intrusive into the expressions
themselves, and can be as transparent as you want. Of course, type inference
also means that you don't have to specify every single type, while still
getting the speed & checking benefit of fully typed code.

~~~
omaranto
Could you show a way to get that code to be generated without any declarations
in the body of the function? I tried something like:

    
    
        (declaim (ftype (function (fixnum fixnum) fixnum) foo) (optimize (safety 0)))
        (defun foo (m n) (* (1+ m) n))
    

That didn't optimize as fully.

~~~
white-flame
You forgot (optimize (speed 3))

~~~
omaranto
I did try with speed 3. Do you mean that:

    
    
        (declaim (ftype (function (fixnum fixnum) fixnum) foo)
                 (optimize (safety 0) (speed 3))
        (defun foo (m n) (* (1+ m) n))
    

should have produced the optimized code (without any generic-*)? It didn't in
my testing on SBCL 1.3.18.

------
KirinDave
I was much more excited about this before I read the article.

------
eecc
[https://www.jetbrains.com/mps/](https://www.jetbrains.com/mps/) ?

------
fcorsitsaroaway
Literally sets an approach that's hit its limits in stone. [And yet people
complain about punctuation.]

Looking forward there will be books on programming with FBE. fbeop will be all
the rage. Naturally we'll discuss the form of code. Is that bulge too far out?
What is better: a plain of declarations that meets a mountain range of control
loops and flow, or, is it better to "sprinkle the frame" with mini frames of
plains and hills? There will be debates. Conferences will be held. Papers will
be presented with analysis of old school code rendered in FBE. There will also
be attempts to finally bring generics to Go, with FBE frontends with little
angular < slots >. Efforts begin to teach monkeys to code.

[p.s. and where exactly is that crab in Fig. 1? Very confusing ..]

