
Swift as a C Language REPL - lelf
https://medium.com/@levwalkin/swift-as-a-c-language-repl-a3cb14199c4c
======
pjmlp
GDB can be used as C language REPL since at least late 90's, and lldb as well.

And if their pseudo-REPL features aren't enough, there are a couple of C
interpreters to choose from.

[http://www.softintegration.com/](http://www.softintegration.com/)

[https://gitlab.com/zsaleeba/picoc](https://gitlab.com/zsaleeba/picoc)

[https://root.cern.ch/cling](https://root.cern.ch/cling)

~~~
ufo
What would I have to do to use gdb as a C repl? I'm not very familiar with gdb
other than using the backtrace to debug segmentation faults.

~~~
pjmlp
Compile your executable with debug info, and then make use of gdb expressions.

[https://sourceware.org/gdb/current/onlinedocs/gdb/Expression...](https://sourceware.org/gdb/current/onlinedocs/gdb/Expressions.html#Expressions)

It is not fully featured REPL, don't expect to use it to create stuff on the
fly, it is more to query and call existing code.

For a proper REPL, check one of the listed interpreters.

~~~
rowanG077
So what you are saying that it's not actually a C REPL. It's a GDB expression
REPL which is very different. What was the original point of your comment?

------
TeMPOraL
A C REPL in ECL (Embeddable Common Lisp):

[https://www.reddit.com/r/lisp/comments/bgwtsh/fun_ecl_hack/](https://www.reddit.com/r/lisp/comments/bgwtsh/fun_ecl_hack/)

It can be as simple as:

    
    
      (defun c-repl ()
        (loop (fresh-line)
              (princ "c99> ")
              (let* ((form (read-line))
                     (func (eval `(let ((*compile-verbose* nil))
                                    (compile nil (lambda () (ffi:c-inline nil nil :void ,form)))))))
                (funcall func))))
      
      > (c-repl)
      c99> printf("HELLO world!\n");
    
      HELLO world!
      c99> { for(int i=0; i<4; i++) printf("*"); printf("\n"); }
      ****
    

(Though that doesn't expose all features of C. More work is required to turn
it into complete REPL.)

Fun thing is, you can just paste the above defun into your ECL REPL and
execute it :).

------
hhas01
Would not be my first choice. A good REPL allows you to write code quickly and
off the top of your head. As article notes, Swift’s C pointer/buffer semantics
are absolutely horrendous, liable to melt the top of your head instead. If you
understand C it just gets in your way. If you don’t understand C it gets in
your way even worse. Working with ObjC classes is cleaner, but even that has
bridging issues.

Incidentally, the Swift REPL itself has another nasty misfeature: it always
outputs the fully introspected debug representation of complex values, rather
than calling `description`/`debugDescription` where available. Not really an
issue when working with pointers, but for native structs and classes with
complex internal state it can print screens and screens of unreadable noise,
totally defeating the purpose. Conversely, the GUI-based “Swift Playgrounds”
REPL prints line output right but lacks the CLI’s persistency so re-evaluates
_all_ lines every time a new line is entered, making it useless for stateful
work.

TL;DR: Swift’s a hairy mess. _[paraphrased jwz aphorism goes here]_

~~~
coldtea
> _As article notes, Swift’s C pointer /buffer semantics are absolutely
> horrendous, liable to melt the top of your head instead_

They look perfectly fine to me. What did you find troubling?

> _TL;DR: Swift’s a hairy mess. [paraphrased jwz aphorism goes here]_

The only mess described thus far is in the REPL/Playgrounds for the language,
which are not themselves "Swift".

~~~
hhas01
There are _ten_ different pointer types, all with different and not easily
memorized APIs.

~~~
coldtea
Well, it's all in the name, no? And the use is rather obvious, mutable vs not,
typed vs not, and buffer types (contiguous memory with count of items) or not.

If only C had those how safer it would be!

~~~
hhas01
“If only C had those how safer it would be!”

Indeed it would be, because then no-one would want to use C.

All languages are abstractions, but there are good abstractions and there are
bad abstractions, and a truly depressing number of Swift abstractions fall
firmly in the “not good” camp.

A well-designed type system abstraction would support and encourage free and
open-ended composition of clearly-defined individual orthogonal concerns. Thus
mutability would be a composable trait, `Mutable<Pointer<…>>`, untyped would
just be `Pointer` without a constaint (Void being the default), and buffers
would likewise be expressed via constraint, `Pointer<Buffer<TYPE,COUNT>>`. But
Swift’s type system was designed by amateurs; its inconsistencies and lack of
expressivity resulting in a stdlib that’s a bloated convoluted mess as it
struggles around those limitations. (Makes even Ruby’s stdlib APIs look clean,
consistent, and concise!)

~~~
SamReidHughes
> But Swift’s type system was designed by amateurs

LOL. The amateurish type system design is the one you've described.
Mutable<Pointer<...>> either makes the wrong thing mutable, or makes too much
stuff mutable. Pointer<Buffer<Type, Count>> would make the whole language more
complicated, and it doesn't solve any of the problems Swift's pointers solve.
The Swift devs in fact are _not_ amateurs, and it shows in how they managed to
keep things simple, instead of convoluting the problem with total I-am-a-very-
smart-Haskell-programmer complexity.

> Thus mutability would be a composable trait

I mean, this is a major tell. You don't just hand-wave mutability being a
composable trait.

~~~
hhas01
“Mutable<Pointer<...>> either makes the wrong thing mutable, or makes too much
stuff mutable.”

You may be reading `Mutable<>` overly literally. I just used generic notation
for familiarity; that doesn’t mean it’d map directly to a struct. Have it be a
`mut[able]` keyword if you prefer. The point is, it can be applied to any
type, and eliminates the need for let _and_ var definitions.

“Pointer<Buffer<Type, Count>> would make the whole language more complicated”

Why? We’ve gone from ten single-purpose types to three general-purpose ones:
Mutable<>, Pointer<>, and Buffer<>. (And, in practice, Buffer would merge with
Data, so really it’s two.)

“The Swift devs in fact are not amateurs, and it shows in how they managed to
keep things simple”

Oh really. There is nothing simple about Swift, a language designed by C++
programmers to be a “better C++”. Just the fact it implements every collection
type (String, Array, Dictionary, Set) twice—once as a class and then again as
a struct—puts the lie to that.

And then, of course, adopted by Apple and bodged into a “better ObjC++”. Which
has even more hair on. See also:

[https://www.quora.com/Which-features-overcomplicate-Swift-
Wh...](https://www.quora.com/Which-features-overcomplicate-Swift-What-should-
be-removed/answer/Rob-Rix)

“You don't just hand-wave mutability being a composable trait.”

And yet, C’s `const` is composable. (Albeit not as a trait of the type itself,
but I can’t think of a reason it couldn’t be.) Plus, with [im]mutability
disentangled from collection implementation and a general purpose “pointer”
for referring specifically to variables, the class+struct duplication can be
eliminated. Let the user describe the behavioral constraints for their code,
and leave the machine to decide when to allocate on heap vs stack and when to
reference-count, single-owner/borrow, or pass-by-value.

I may not know much about compiler engineering, but I do have a bit of
experience in (Lisp-y) language design. Whereas the Swift team are compiler
engineering wizards (no contest), but compiler engineers do not necessarily
make good language designers (since they’re liable to design it to suit the
language’s compiler engineers rather than its end users).

~~~
SamReidHughes
Your idea of complexity is totally backwards. Swift has some types that do
different things. Maybe you could add features, thought out to a vague level,
that infect every part of the type system, and require redesigning major parts
of how the language works, so you can define a few less types! C/C++ have
const [which doesn't work well], so _surely_ you can just throw such a notion
into Swift's type system! Well that's not gonna make the language simpler.

Go make a statically typed language with Mutable<>, in some form. Then talk.

------
solidsnack9000
There is the germ of an idea here, for sure. It is very easy to map C
libraries to Swift. Binding LibPQ, for example, requires just a five line
"module map" file:

[https://github.com/solidsnack/CLibPQ/blob/master/module.modu...](https://github.com/solidsnack/CLibPQ/blob/master/module.modulemap)

Once you've mapped in the library, trying it out interactively in Swift is
easy and fun because of Swift's high-level features.

------
brobot182
Maybe if you had some super-short typealiases it would work, e.g. ‘typealias
UnsafeRawPointer = URP’. Otherwise, you get bogged down with all the casting
and other FFI stuff. One alternative besides gdb is cling:
[https://root.cern.ch/cling](https://root.cern.ch/cling)

------
j_m_b
So `let` is being used to define a var that is lexically scoped to... the
global environment?! I've noticed you can do this in Javascript as well. As a
Lisp programmer, its very jarring and seems like a bad practice. Is there a
reason you would do this?

~~~
dlivingston
In Swift, IIRC, `let` defines a constant reference to a value within the
current scope.

~~~
hhas01
Correct. `let` = constant binding, `var` = variable binding, and except for
top-level (global) declarations they are always block scoped.

BUT, there is a gotcha: this “constantness” only applies to the name-value
binding, not to the value itself. Thus you can still mutate the content of a
let-bound value when that value is a class or class instance. Which kinda
defeats the point of having the let/var distinction in the first place. C’s
`const` may have its priorities backwards, but least it does what it says on
the tin.

(And let’s not mention what a PITA Swift gets when you want to work with the
contents of complex nested struct-based collections in a language that doesn’t
have native pointers/references. Again, it makes C look good.)

