
Single-Assignment C - lelf
http://www.sac-home.org/doku.php
======
WalterBright
I thought this was about adopting a programming style where each variable is
assigned to only once. But it was something else entirely.

I was interested because I've started adopting the single assignment style in
my own code, and like the results (the code is easier to comprehend).

~~~
glouwbug
Agreed, I'm currently taking a similar approach, but forgoing pointers as much
as possible as well. This leads to structs being passed by value, and const
abuse.

    
    
        Ray h_cast(const Hero hero, const Hit hit, const Sheer sheer, const int yres, const int xres)
        {
            const Point end = p_sub(hit.where, hero.where);
            const Point corrected = p_turn(end, -hero.yaw);
            const Line trace = { hero.where, hit.where };
            const Projection projection = p_project(yres, xres, hero.fov.a.x, hero.pitch, corrected, hero.height);
            const Ray ray = { trace, corrected, p_sheer(projection, sheer), hit.surface, hit.offset, hero.torch };
            return ray;
        }  
    

It leads to some nice somewhat functional styles. I estimate its 80% pure,
given its C99 alone. I've adopted this style in my Age of Empires 2 engine
rewrite if anyone is curious:
[https://github.com/glouw/openempires](https://github.com/glouw/openempires)

As for performance I am heavily relying on LTO. I seem to get a 50%
performance boost with pass by values on structs - as I've sedded openempires
to replace occurrences of _Type name_ with C++'s _Type& name_ for all
functions arguments - and the added pointer aliasing and de-references bogged
the engine down in heavily forested areas.

Compilers love singly assigned const values, and seem to suffer under heavy
pointer aliasing.

~~~
voldacar
> This leads to structs being passed by value

do compilers generally optimize this away on -O3, or do you just accept the
performance hit in exchange for prettier code?

~~~
asymptotically2
If it's a static method (or in an anonymous namespace in C++), it should get
fixed at any optimisation level. However if it's a global method, you'll need
to pass -flto to defer optimisations to link time to make it work.

------
kick
This is interesting; I just investigated SAC for the first time about seven
hours ago (I actually posted a license-fragment from it on my social media
account:
[https://blob.cat/notice/9qMowPTjR9F7fjid3Q](https://blob.cat/notice/9qMowPTjR9F7fjid3Q)),
finding it technically impressive but unfortunately proprietary.

Was there news about it, or something? It came to mind because something I was
wanting to try depended on it, and it doesn't get posted to HN very often, so
I'm really curious as to how you found it.

~~~
Athas
What did you find that depends on SaC?

~~~
kick
An ancient APL compiler, unfortunately. A really cool one, too!

~~~
Athas
APEX? Does it still work?

~~~
kick
Possibly! I didn't try it: I don't use proprietary software.

------
coldtea

      p = p + v * dt;
      v = v + a * dt;
    

How is this "single assignment"? Aren't v and p assigned values already before
those lines? Or do they have some default initial value for their type that
doesn't count as an assignment?

~~~
Arnavion
It's not C, but a new language with similar syntax. Based on reading the docs
at [1], the assignment is sugar for generating a new binding for the result of
that expression that shadows the previous one.

[1]: [http://www.sac-home.org/doku.php?id=about:core](http://www.sac-
home.org/doku.php?id=about:core)

~~~
nwallin
I don't understand.

What does the "single assignment" bit get you that a compiler with an SSA pass
doesn't?

~~~
gengkev
Probably that the original binding of p is immutable, as it would be in a
functional language: you can create a new binding, but you can't actually
change the value of the existing binding.

~~~
nwallin
Unless there's something I don't understand, that's what the single static
assignment pass does in a compiler.

~~~
AgentME
New bindings live at different addresses (if you pass a pointer to one
binding, and then make a new binding with a new value, the existing pointer
will point to the old value and not the new binding's value) and bindings made
in a loop iteration won't live to the next iteration.

~~~
lostmsu
This sounds like an implementation detail. What does the language spec say
about the outcome.

~~~
a1369209993
The (C) language spec says that:

    
    
      x = 5;
      int* p = &x;
      x = 6; // new binding of x
      printf("%i\n",*p);
    

prints "6". If new bindings lived at different addresses, it would print "5".

------
dang
Related from 2013:
[https://news.ycombinator.com/item?id=6949525](https://news.ycombinator.com/item?id=6949525)

~~~
jagged-chisel
I think you mean 2013

~~~
dang
Ah yes. Thanks! Fixed.

------
HeraldEmbar
The home page is fairly free of any details about SaC, though I do now know an
awfully lot about who is involved. Also, there's no reference manual.

Where can I find a tutorial, examples, or any concrete details?

~~~
antonvs
There's a docs page linked from the home page with a tutorial and various
other docs:

[http://www.sac-home.org/doku.php?id=docs:main](http://www.sac-
home.org/doku.php?id=docs:main)

