lainchan / λ
ITT: A E S T H E T I C code snippets
threebsd · 2017-04-17 16:32
This one is based on an example in "Modern C"
C
char const* sign_repr[4] = {
"something weird",
"sign and magnitude",
"ones' complement",
"two's complement"
};
enum {sign_magic = -1&3}; /* A E S T H E T I C */
printf("Sign representation used on this computer is %s\n", sign_repr[sign_magic]);
SHODAN · 2017-04-17 17:00
This is APL for when I need e, more accurate for larger n: e←+/÷!(-⎕IO)+⍳n
There's an explanation for how it works in the APL thread, if anyone is wondering.
I also find this program for finding primes to be aesthetically pleasing: (~R∊R∘.×R)/R←1↓ιR
gitgood · 2017-04-17 17:33
>>430
I've always liked the XOR swap algorithm for swapping two variables without a temp variable.
void swap(int* a, int* b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
I'd advise everyone to *never* use this though. It's somewhat hard to reason about if you've never seen this trick before, and from some tests I did a while ago it seems to be slower than using a temp variable.
Still clever though.
Nameless · 2017-04-17 18:16
>>434
sorry for being an idiot, but how does this work? I am very confused
gitgood · 2017-04-17 18:35
>>435
First, you have to understand what XOR *is*.
It's a logical operation that only outputs true when its inputs differ.
Here's a truth table that might help:
A|B|output
----------
0|0|0
0|1|1
1|0|1
1|1|0
You can clearly see when input A is 1 and B is 0, it outputs true (and vice versa).
Now, consider two numbers. Lets use 6 and 4 because they're nice and small.
The binary representation of 6 is:
0110
The binary representation of 4 is:
0100
The first line of the function is XORing the variables a and b, and storing the result in a.
Lets say a = 6, b = 4.
*a ^= *b
This translates to:
0110 (a)
XOR 0100 (b)
--------
a = 0010 (2)
The variable a now points to "0010", or 2 in base 10.
The next line is:
*b ^= *a
This translates to:
0010 (a)
XOR 0100 (b)
--------
b = 0110 (6)
Awesome, variable b now contains the number 6!
The next line is:
*a ^= *b;
This translates to:
0010 (a)
XOR 0110 (b)
--------
a = 0100 (4)
The variable a now contains the number 4.
We started with 6 in a and 4 in b, now we have 4 in a and 6 in b. Magic!
I apologise if the formatting of this gets all fuarrrked up.
Unsigned · 2017-04-17 19:03
>>430
if that's aesthetic in C I'd hate to see what ugly C code looks like
oh wait
Cat Mother · 2017-04-17 19:07
"Aesthetic" is one of the worst things to come out this generations of pretentious soykaflords on the internet.
I don't see anything particularly striking in that snippet of code, other than the comment.
JARGON · 2017-04-17 19:34
>>436
nice, I get it. thanks for the explanation lainon
sandinmyass · 2017-04-17 19:54
>>441
fair enough, but then consider contributing to this thread by posting something you'd consider "particularly striking"
John Titor · 2017-04-17 20:50
>>440
GNU source code
Wirth · 2017-04-17 20:52
>>434
>from some tests I did a while ago it seems to be slower than using a temp variable.
Correct! This trick is more space efficient but less time efficient. With how abundant memory is these days there's no reason to use it, but I do like it too, and it helps demonstrate a property of XOR, namely
a ^ b ^ b = a
a ^ b ^ a = b I like to think of a ^ b as a "key" which, when given one value, shows the other. IIRC this has uses in cryptology but it's been awhile since I've dove into that (and I never got very far anyway).
Morpheus · 2017-04-17 21:46
>>446
>and it helps demonstrate a property of XOR
the proof is trivial, it's just noting that
a xor 0 = a
a xor a = 0
Debbie Charteris · 2017-04-17 21:56
>>447
Sure! Though when you present it that way it might look more like a special case of 0 to a beginner.
Bobby Newmark · 2017-04-19 04:57
"For each" loop macro in C, works with any contiguous section of memory.
#include <stdio.h>
#define FOR_EACH(p, start, n) for ((p) = (start); ((p) - (start)) < (n); ++(p))
int
main(void)
{
long *iter;
long arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
FOR_EACH(iter, arr, 10) {
printf("%d\n", *iter);
}
}
SHODAN · 2017-04-19 16:34
>>434
>from some tests I did a while ago it seems to be slower than using a temp variable
It is because of superscalar architectures (CPU pipelines) and compiler optimizations. Basically, in
x := x XOR y
y := x XOR y
x := x XOR y all operations have to wait on the ones above to be completed, thus they need to be executed strictly sequentially. On the other hand, in
tmp := x
x := y
y := tmp the last two operations have to wait on the first, but can otherwise be executed in any order with respect to each other. This, on a pipelined CPU, means they get executed almost completely in parallel. Also, decent compilers will only allocate tmp on a register without ever committing its contents to RAM (which would indeed make things a few orders of magnitude slower with the XOR algorithm).
Torvalds · 2017-04-19 16:59
The following is a simple C++11 implementation of a Fenwick tree:
#include <vector>
#include <cassert>
template <class T>
class fenwick
{
private:
std::vector<T> m_a;
inline size_t parent(const size_t i) const
{
return i - (i & -i);
}
inline size_t get_next(const size_t i) const
{
return i + (i & -i);
}
public:
fenwick(const size_t n)
: m_a(n + 1)
{
assert(n > 0);
}
void add(const size_t i, const T k)
{
assert(i >= 0);
int cur = i + 1;
do {
m_a[cur] += k;
} while ((cur = get_next(cur)) < m_a.size());
}
int prefix_sum(const int i) const
{
assert(i >= 0);
int cur = i + 1;
int sum = 0;
do {
sum += m_a[cur];
} while ((cur = parent(cur)) != 0);
return sum;
}
}; Fenwick trees (or BIT trees) are data structures used to efficiently update and query prefix sums of integer arrays. The founding blocks are those "parent" and "get_next" operations, which are just wonderfully simple one-liners of bit arithmetic. When I first saw this stuff it blew my mind.
Sipho Nkosi · 2017-04-19 20:43
>>515
Nice, but
> Two space indents
XERXES · 2017-04-19 21:02
>>515
Oh god, do I fuarrrking hate Fenwick trees. So confusing. They aren't even trees to begin with!
Mitnick · 2017-04-19 21:25
>>522
But they are, just represented with an array, like you do for heaps. Matter of fact, succint data structures for tree representation all work with bit vectors and bit operations and they're all brilliant solutions imho.
array · 2017-04-19 22:01
>>515
The bit magic is sweet!
In case anyone is wondering:
The expression i - (i & -i) flips the rightmost set bit to 0 since -i is defined as SIZE_MAX+1 - i (subtracting from SIZE_MAX is effectively the same as negating all the bits of i; now adding 1 --- since we actually subtract from SIZE_MAX+1 --- carries through the 1 until it "reaches" the first 0, that is the first bit that was set to 1 in i.)
Therefore ANDing -i with i yields the bit pattern with just the rightmost set bit of i, and subtracting that from i just means leaving out the least significant set bit.
Holy soykaf, I suck at explaining stuff.
dictionary · 2017-04-21 14:40
I guess I have one. This came from a silly programming challenge to print the following:
*
**
***
****
*****
******
*******
*******
My """elegant""" C solution is:
#include <stdio.h>
int main(void) {
const char* s = "\0********" + 9;
while (*--s)
puts(s);
}
Mario Rossi · 2017-04-21 16:28
>>572
that's clever!
Fred Nurk · 2017-04-21 18:49
>>572
C novice here: why the const and the +9 at the end?. Complete explanation would be excellent but a few pointers (no pun intended) wouldn't hurt.
Agent Jones · 2017-04-21 18:55
>>577
The 'const' just makes the string constant.
The +9 sets the char* (pointer to char) at the end of the string (after the \0 and the 8 *'s, before the (implicit) null terminator).
Each iteration, the pointer is decreased, going back one * and prints it.
The loop terminates when the while test finds the first \0 (*s = 0)
dictionary · 2017-04-21 18:56
>>578
>and prints it
s/it/the * chain starting at that position/
pop · 2017-04-21 19:07
>>578
Ahh now I get it, very nice indeed. Against all the books' clear code rules but really pleases my glands.
I remember once writing a really neat recursive function to add up all the members of a tree and count the branches, was really fun work doing that but rarely does opportunity for that manifest itself. It was from the build your own lisp book btw. Having custom datastructures handled recursively is really therapeutic.
Joey · 2017-06-02 21:48
I revive with this single page J interpreter:
typedef char C;typedef long I;
typedef struct a{I t,r,d[3],p[2];}*A;
#define P printf
#define R return
#define V1(f) A f(w)A w;
#define V2(f) A f(a,w)A a,w;
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
I *ma(n){R(I*)malloc(n*4);}mv(d,s,n)I *d,*s;{DO(n,d[i]=s[i]);}
tr(r,d)I *d;{I z=1;DO(r,z=z*d[i]);R z;}
A ga(t,r,d)I *d;{A z=(A)ma(5+tr(r,d));z->t=t,z->r=r,mv(z->d,d,r);
R z;}
V1(iota){I n=*w->p;A z=ga(0,1,&n);DO(n,z->p[i]=i);R z;}
V2(plus){I r=w->r,*d=w->d,n=tr(r,d);A z=ga(0,r,d);
DO(n,z->p[i]=a->p[i]+w->p[i]);R z;}
V2(from){I r=w->r-1,*d=w->d+1,n=tr(r,d);
A z=ga(w->t,r,d);mv(z->p,w->p+(n**a->p),n);R z;}
V1(box){A z=ga(1,0,0);*z->p=(I)w;R z;}
V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
A z=ga(w->t,1,&n);mv(z->p,a->p,an);mv(z->p+an,w->p,wn);R z;}
V2(find){}
V2(rsh){I r=a->r?*a->d:1,n=tr(r,a->p),wn=tr(w->r,w->d);
A z=ga(w->t,r,a->p);mv(z->p,w->p,wn=n>wn?wn:n);
if(n-=wn)mv(z->p+wn,z->p,n);R z;}
V1(sha){A z=ga(0,1,&w->r);mv(z->p,w->d,w->r);R z;}
V1(id){R w;}V1(size){A z=ga(0,0,0);*z->p=w->r?*w->d:1;R z;}
pi(i){P("%d ",i);}nl(){P("\n");}
pr(w)A w;{I r=w->r,*d=w->d,n=tr(r,d);DO(r,pi(d[i]));nl();
if(w->t)DO(n,P("< ");pr(w->p[i]))else DO(n,pi(w->p[i]));nl();}
C vt[]="+{~<#,";
A(*vd[])()={0,plus,from,find,0,rsh,cat},
(*vm[])()={0,id,size,iota,box,sha,0};
I st[26]; qp(a){R a>='a'&&a<='z';}qv(a){R a<'a';}
A ex(e)I *e;{I a=*e;
if(qp(a)){if(e[1]=='=')R st[a-'a']=ex(e+2);a= st[ a-'a'];}
R qv(a)?(*vm[a])(ex(e+1)):e[1]?(*vd[e[1]])(a,ex(e+2)):(A)a;}
noun(c){A z;if(c<'0'||c>'9')R 0;z=ga(0,0,0);*z->p=c-'0';R z;}
verb(c){I i=0;for(;vt[i];)if(vt[i++]==c)R i;R 0;}
I *wd(s)C *s;{I a,n=strlen(s),*e=ma(n+1);C c;
DO(n,e[i]=(a=noun(c=s[i]))?a:(a=verb(c))?a:c);e[n]=0;R e;}
main(){C s[99];while(gets(s))pr(ex(wd(s)));}
Tyrell Wellick · 2017-06-03 19:54
fav
float InvSqrt( float number )
{
long i;
float x2, y;
const float threehalfs = 1.5F;
x2 = number * 0.5F;
y = number;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the fuarrrk?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
//y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration, this can be removed
return y;
}
source code above is from quake 3 but supposedly this stretches back to 1986 from the guy that standardised floats in IEEE-754-1985
not too difficult conceptually: to compute 1/sqrt(x) where x is float, alias as int to allow bit-level manipulation, then let new exponent = -0.5(old constant) (y = x^-0.5 => log(y) = -0.5(logx)), with constant added to correct mantissa/overflow, followed by a newton method to approximate the first guess
derivation of the constant takes a little more work in fairness (https://www.lomont.org/Math/Papers/2003/InvSqrt.pdf) but still only really requires knowledge of how floats work
pretty redundant now because of SSE RSQRTSS and probably throws warnings like crazy for the pointer tomfoolery but still breddy gud
Splicer · 2017-06-04 10:15
>>444
I'd like to suggest conventionally beautiful and aesthetic code is code that fills a set of qualifications:
1. It works.
2. It intuitively makes sense to you when you read it. (This is clearly a value jugement by the reader.)
3. It actually runs in the way you would think it runs upon reading it.
The problem with some threads like this is people playing code golf around their personal preference of languages highly specific ambiguous feature that makes the code essentially unreadable. After you learn a couple languages the: "that one *obscure-feature-of-language-x* is the coolest thing ever!" mentality loses a bit of its luster.
I'm not saying low level, obfuscated or ambiguous solutions do not have their own appeal, but that they do not have the same conventional aesthetic as a well written obvious piece of code that solves one problem well.
list · 2017-06-04 19:36
>>572
imo
#include <stdio.h>
int main(void)
{
for (int i = 1; i < 9; i++)
printf("%.*s\n", i, "********");
}
emphasis · 2017-06-04 19:47
>>1619
>"no fun allowed"
Yeah, writing clear an obvious programs is good when you actually want to be productive, but usually the clear obvious solution is also long and boring. Golfing can be fun. Misusing a feature for unexpected (but useful) results is fun. It's impressive to see somebody with complete mastery over a language be able to apply that knowledge in clever ways.
Not that I really think that either of those are "aesthetic"; I'm not sure what the OP meant.
Jane Doe · 2017-06-04 22:44
>>1633
>>"no fun allowed"
I'm not saying that.
>but usually the clear obvious solution is also long and boring.
That's debatable just like any other value judgement.
>Golfing can be fun. Misusing a feature for unexpected (but useful) results is fun. It's impressive to see somebody with complete mastery over a language be able to apply that knowledge in clever ways.
I agree but I think it's important to remember that it is also just as impressive to solve problems in a smart easy to understand manner.
I'm not claiming only one kind of code can be aesthetically attractive. My point is basically the opposite of that, but also that often people get too stuck in the mentality of writing cryptic hard to understand code for no real reason besides code golfing.
A simple example of the kind of could I am talking about would be binary search. Binary search is easy to understand once you get the main ideas, it solves the problem of searching in an interesting manner, and it is not super "golfy"
Lukasiewicz · 2017-06-05 21:46
I always liked this one:
(create-ns 'recipe)
(alias 'r 'recipe)
(s/def ::r/name string?)
(s/def ::r/description string?)
(s/def ::r/ingredients (s/coll-of ::i/ingredient :gen-max 3))
(s/def ::r/steps (s/coll-of string? :gen-max 3))
(s/def ::r/servings ::c/pos-num)
(s/def ::r/recipe (s/keys :req [::r/name]
:opt [::r/description ::r/ingredients ::r/steps ::r/servings]))
(s/conform ::r/recipe toast)
(s/exercise ::r/recipe)
That call to exercise will return example recipes, which look like this:
(def toast
#:recipe{
:name "Buttered toast"
:description "Like bread, but more tasty"
:ingredients [
#:ingredient{:name "bread" :quantity 2 :unit :slice}
#:ingredient{:name "butter" :quantity 1 :unit :teaspoon}]
:steps ["Toast two slice of bread in the toaster."
"Spread butter on toast."]
:servings 1})
Trinity · 2017-06-07 00:27
>>1649
Which Lisp is that?
Splicer · 2017-06-07 00:31
I think pic related is pretty aesthetic.
Torvalds · 2017-06-07 09:25
>>1662
create-ns and def would suggest Clojure, though I'm not sure what that example's supposed to be.
x<->y · 2017-06-07 10:23
>>1608
>// what the fuarrrk?
a classic
Joe Bloggs · 2017-06-07 18:48
>>1662
Yeah, that's Clojure.
(The #:guy {:name "abe"} type of code will only work on the latest version).
And what it does is a bunch of things. One is make a runtime checker for ensuring data is a certain shape. Another is the ability to generate sample recipes.
If you spec functions too, you can even use quickcheck to test them for free.
have a look here and lmk? http://blog.klipse.tech/clojure/2016/05/30/spec.html
Motoko Kusanagi · 2017-06-08 12:22
>>1669
>If you spec functions too, you can even use quickcheck to test them for free.
Cool. I really like property-based testing, I'm happy to see that it's spread/spreading to lots of languages. The Isabelle proof assistant has a cool use of QuickSpec where it tries to find counterexamples to lemmas for you before you go through the effort of trying to prove it. Really neat.
Bobby Newmark · 2017-06-09 05:02
>>1677
It's the best isn't it?
Here's an example. Its so cool @_@;
So, subs lets you take substrings like this
(subs "abcdefg" 3 6)
;;=> "def"
So, the spec you'd add to the function looks like this:
(s/fdef clojure.core/subs
:args (s/and (s/cat :s string? :start nat-int? :end (s/? nat-int?))
(fn [{:keys [s start end]}]
(if end
(<= start end (count s))
(<= start (count s)))))
:ret string?
:fn (fn [{:keys [args ret]}]
(let [{:keys [s start end]} args]
(<= (count ret) (- (or end (count s)) start)))))
Not exactly painless, but now we can quickcheck the function like this
(s/check)
and we know :fn from above holds, more or less.
Elliot Alderson · 2017-09-06 14:20
>>1632
I like your version a lot. The only part I don't understand is ".*s". My guess is that the dot represents the number of characters "allowed" to be printed?
Church · 2017-09-06 15:16
>>1608
This is by far my favourite piece of code in history
Hiro Protagonist · 2017-09-07 01:53
>>1632
Very cool but how does the dot work?
Tequila · 2017-09-07 03:44
>>3269
>>3281
From man 3 printf :
An optional precision, in the form of a period ('.') followed by an optional decimal digit
string. Instead of a decimal digit string one may write "*" or "*m$" (for some decimal integer
m) to specify that the precision is given in the next argument, or in the m-th argument, respec‐
tively, which must be of type int. If the precision is given as just '.', the precision is
taken to be zero. A negative precision is taken as if the precision were omitted. This gives
the minimum number of digits to appear for d, i, o, u, x, and X conversions, the number of dig‐
its to appear after the radix character for a, A, e, E, f, and F conversions, the maximum number
of significant digits for g and G conversions, or the maximum number of characters to be printed
from a string for s and S conversions.
array · 2017-09-07 10:20
I find this way of printing a comma-separated list of items very clever:
int ary[] = { 42, 1337, 0x1badb002 };
const char * prefix = "";
for(size_t i = 0; i < sizeof(ary) / sizeof(ary[0]); i++) {
printf("%s%d", prefix, ary[i]);
prefix = ", ";
}
putchar('\n')
John Peters, You Know, the Farmer · 2017-09-07 14:18
>>3288
Holy fuarrrk that's clever.
I say this as a moron that spent at least three hours trying to get the CSV formatting right for a text-to-csv converter.
I have failed all of you
for(index = 0, col_counter = 0; index < NUM_ROWS * NUM_COLS; index++)
{
temp = *(data + index);
output_csv << temp;
if(col_counter < NUM_COLS - 1)
output_csv << ",";
col_counter++;
if(col_counter == NUM_COLS )
output_csv << "\n",
col_counter = 0;
}
Cypher · 2017-09-07 18:28
Here's a nice little function for calculation of sum-of-divisors of a number that i found back in 2015...
int sum_of_divisors(int n)
{
int sum = 1;
for(int k = 2; k * k <= n; ++k)
{
int p = 1;
while(n % k == 0)
{
p = p * k + 1;
n /= k;
}
sum *= p;
}
if(n > 1)
sum *= 1 + n;
return sum;
}
Joey · 2017-09-07 18:38
>>3305
What the fuarrrk.
int sum_of_divisors(int n)
{
int sum = 1;
for(int k = 2; k * k <= n; k++)
{
int p = 1;
while(n % k == 0)
{
p = p * k + 1;
n /= k;
}
sum *= p;
}
if(n > 1)
sum *= 1 + n;
return sum;
}
Why doesn't this soykaf support tabs
BloodCat · 2017-09-09 16:11
JS has some interesting properties now that I'm taking a deep dive into its specifications for work. Example from a book:
function multiplier(factor) {
return function(number) {
return number * factor;
};
}
var twice = multiplier(2);
console.log(twice(5));
// -> 10
I haven't studied functional languages enough to have had this exposure to closures before but find it cool. The "freezing" of chunks of code is rad.
HELIOS · 2017-09-09 22:40
I was working with some audio data and wanted to examine it in the console:
char wave_to_char(float f)
{
if(f < -0.75f)
return '_';
if(f < -0.50f)
return ',';
if(f < -0.25f)
return '.';
if(f < -0.00f)
return '-';
if(f < 0.25f)
return '~';
if(f < 0.50f)
return '*';
if(f < 0.75f)
return '\'';
return '`';
}
Six · 2017-09-09 23:21
>>3367
Mind giving some context here?
Im interested in getting into audio programming in Linux eventually. I have some familiarity with digital audio (programming the occasional DSP for work).
Technician · 2017-09-10 04:08
>>3368
I actually haven't don't much native linux audio programming; I was just outputting some raw data to feed into my daw.
But anyway, here's a sine wave:
~~*''```````''*~~-.,,_______,,.--~*''```````''*~~-.,,_______,,.--~*''```````''*~~-.,,_______,,.--~*''```````''*~~-.,,_______,,.-
Ishikura "Tatsu" Tatsuhiko · 2017-09-10 04:09
>>3375
*done much
Cutter · 2017-09-10 11:20
>>3367
Wouldn't rewriting it using a for loop like this:
c
#define countof(ary) (sizeof(ary) / sizeof((ary)[0]))
char wave_to_char(float f)
{
static const char chars[] = "_,.-~*'`";
float threshold = -0.75;
for(size_t i = 0; i < countof(chars) - 2; i++) {
if(f < threshold)
return chars[i];
threshold += 0.25;
}
return chars[countof(chars) - 2];
} be a good idea? It makes it easier to add new chars or change the existing ones.
Drifter · 2017-09-10 18:23
>>3367
>>3381
char wav_to_char(const float f)
{
return "_,.-*`''"[(unsigned char)((f + 1.f)*(7.f/2.f))];
} sine wave:
-*`'''`*-.,___,.-*`'''`*-.,___,.-*`'''`*-.,___,.-*`'''`*-.,___,.-
let · 2017-09-10 19:15
>>3385
Beautiful.
Unspecified · 2017-09-10 23:02
>>3385
>>3381
Hahaha great. It was a one off function; I don't know how you plan to get more resolution out of ascii characters, but more power to you.
Hopper · 2017-09-11 00:12
>>3385
How does that work? I compiled it and it doesn't print a sine wave.
Crash Override · 2017-09-11 02:23
>>3392
that's not the whole thing.
#include <stdio.h>
#include <math.h>
char wav_to_char(const float f)
{
return "_,.-*`''"[(unsigned char)((f + 1.f)*(7.f/2.f))];
}
int main(void)
{
float f;
for(f=0.f; f<(8.f*M_PI); f+=(M_PI/8.f))
putc(wav_to_char(sin(f)), stdout);
putc('\n', stdout);
return 0;
}
HELIOS · 2017-09-19 22:51
>>1596
just read the wiki on this, what an interesting language
Unknown · 2018-03-11 04:23
>>3353
First class functions, my dude. You can also do this in Go, btw.
Also in ES6+ this gets a lot prettier:
let multiplier = factor => number => number * factor
let twice = multiplier(2)
console.log(twice(5))
藤原純一 · 2018-03-11 15:25
>>502
>Using macros to replace a control structure
Now that's some fuarrrking next level disgusting soykaf right there.
Tequila · 2018-03-11 15:29
>>1608
I can never read this code again without remembering Karlie.
Dozer · 2018-03-11 18:36
>>7242
This dichotomy is not men vs women it's beginners vs people who know the language they're using and don't need to use comments to translate every line of code into English.
McCarthy · 2018-03-11 19:48
>>7242
I genuinely hope that image is a joke.
Lunch · 2018-03-12 19:51
>>7242
>It is hacker code used to steal nude photos!
Knuth · 2018-03-13 04:43
>>7242
Ugh
Cypher · 2018-03-14 05:37
>>7242
Huh, I knew I had seen that code before: https://hackaday.io/ (on the dudes computer)
Decided to look it up, it was done by the absolute madmen behind Quake.
John Carmack you magnificent bastard.
Emmanuel · 2018-03-14 11:01
>>445
Oh god, I am triggered. The only thing worse than GNU source code is the Windows API.
Unspecified · 2018-03-14 11:13
>>1608
>probably throws warnings like crazy for the pointer tomfoolery
Just disable strict aliasing. It's a C standard feature that was lifted out of Fortran because muh speed and it does way more harm than good given how common reinterpreting pointers is. Systems programming people are better off without it.
Bob Arctor · 2018-03-15 00:51
A minimal scheme interpreter written in scheme. From https://www.youtube.com/watch?v=OyfBQmvr2Hc
[code=Lisp]
(require racket/match)
(define eval-expr
(lambda (expr env)
(match expr
; boring bit to make the example work
[n #:when (number? n) n]
[(list 'sub1 e)
(sub1 (eval-expr e env))]
[(list 'zero? e)
(zero? (eval-expr e env))]
[(list '* e1 e2)
(* (eval-expr e1 env) (eval-expr e2 env))]
[(list 'if t c a)
(if (eval-expr t env)
(eval-expr c env)
(eval-expr a env))]
; the exciting part:
; look up symbol in the environment
[x #:when (symbol? x) (env x)]
; evaluate lambda expressions
[(list 'lambda (list x) body)
(lambda (arg)
; evaluate body in new environment
(eval-expr body (lambda (y)
(if (eq? x y)
arg
(env y)))))]
; single argument functions
[(list rator rand)
((eval-expr rator env) (eval-expr rand env))])))
; evaluating a factorial program
(eval-expr
'(((lambda (!)
(lambda (n)
((! !) n)))
(lambda (!)
(lambda (n)
(if (zero? n)
1
(* n ((! !) (sub1 n)))))))
5)
; empty environment
(lambda (x) (error 'lookup "nothing")))
[/code]
Sabo Engle · 2018-03-15 03:26
Honestly all of knuth's stuff is aesthetic
https://people.sc.fsu.edu/~jburkardt/c_src/ladders/
John Rain · 2018-03-15 10:30
>>7313
>Honestly all of knuth's stuff is aesthetic
Are you aware of the word count challenge between Donal Knuth and Doug McIlroy (one of the very first Unix developers)?
>Read a file of text, determine the n most frequently used words, and print out a sorted list of those words along with their frequencies.
Knuth wrote a 10 page Pascal program to solve it and McIlroy wrote a shell 1 liner.
http://www.leancrew.com/all-this/2011/12/more-shell-less-egg/
Knuth is way overrated.
Leto Atreides I · 2018-03-15 18:10
>>7320
A fairer comparison would be to count the source code of each of the binaries McIlroy used in his shell script.
let · 2018-03-15 19:27
>>7323
>A fairer comparison would be to count the source code of each of the binaries McIlroy used in his shell script.
No it wouldn't. You don't count that for the same reason you don't count the lines of code in the Pascal compiler.
William Holtzer · 2018-03-15 22:17
>>7325
Nope. If that were the case, you'd need to count lines from the shell source code as well. It's not even a pure shell solution since it uses entirely separate programs. It's not hard to write a C program that spawns and interconnects processes. You can probably beat the shell script using python and importing some library.
Nobody special · 2018-03-16 00:19
>>7329
>If that were the case, you'd need to count lines from the shell source code as well
You mean the shell interpreter? You don't count the loc of the shell interpreter in McIlroy's solution for the same reason you don't count the loc of the operating system in Knuth's solution.
I appreciate you want to draw an arbitrary line in the sand where counting stops in a way that favor's Knuth but that's missing the point.
The point is Knuth went away and designed an over engineered algorithm and wrote a whole lot of verbose, single purpose code. McIlroy leveraged a powerful toolset to pipe together existing code in a flexible way with minimal waste. Which one is the hacker and which one is the down syndrome?
Nobody special · 2018-03-17 04:30
>>7332
The OS has nothing to do with it. The fact is the pascal compiler is the pascal language's implementation, just like sh/bash/whatever is the shell script's language implementation.
Shell script hacks might win you some Unix points with the impressionable crowd, but the fact is the "down syndrome" approach is the one that actually works. Github is an easy example: they used to wrap around the git binary but shelling out was so expensive they eventually reimplemented git in pure Ruby to make things better, and then people eventually came up with libgit2.
queue · 2018-03-17 10:08
>>7332
This is a terrible cherry-picked example to demonstrate the supposed "power" and "flexibility" of shell scripts over actually good programming languages; everybody knows Knuth is a junkie who will go out of his way to overengineer even the simplest things, and his solution being verbose and overengineered does not make all solutions that are not based on shell scripts verbose and overengineered.
The shell is nothing but a gimped programming language that happens to be designed for interactive use, and its standard library is a terrible mess full of byzantinisms and idiosyncrasies. The unix shell has more than overstaid its welcome and I wish it would die already, but unfortunately nobody has taken it upon themselves to kill it just yet.
Jim Hilger · 2018-03-17 11:16
>>7345
>Github is an easy example: they used to wrap around the git binary but shelling out was so expensive they eventually reimplemented git in pure Ruby to make things better, and then people eventually came up with libgit2.
You mean they did the simplest thing that works and then moved onto a more complicated approach as their requirements changed? I think you are still missing the point. The moral of the story is that Knuth wasted time and effort by doing an overengineered solution *first* and was then blown out of the water by a shell 1-liner which met the requirements just as well. Life is not an rpg, you don't get extra exp points for every useless line of code you write.
>>7347
>[Knuth's] solution being verbose and overengineered does not make all solutions that are not based on shell scripts verbose and overengineered.
Nobody said that. The purpose of this subthread was to demonstrate to a starryeyed beginner that Knuth really isn't that great ( >>7313).
>The unix shell has more than overstaid its welcome and I wish it would die already, but unfortunately nobody has taken it upon themselves to kill it just yet.
That's not true. Microsoft tried with powershell. Plan9 tried with rc. Oil is having a good go at the moment. Like many things Unix though, the concept is earthshattering powerful and the implementation is so simple and surprisingly difficult to improve upon.
Chan Siu Ming · 2018-03-17 13:17
>>7348
>The purpose of this subthread was to demonstrate to a starryeyed beginner that Knuth really isn't that great
Fair enough.
>That's not true. Microsoft tried with powershell. Plan9 tried with rc. Oil is having a good go at the moment.
rc and Oil are just reimplementations of the same thing whose goal is mostly to improve readability and behavior.
rc still treats everything as strings and streams of bytes, so it is not such a huge improvement.
From what I understand Oil plans to have some kind of convention for processing structured data, but for the most part it's still hampered by maintaining compatibility with existing tools. The language is better defined than most existing shells so it's a noble attempt, but it's still an attempt to put lipstick on a pig.
Now, Powershell definitely is a step in the right direction, but the UX is horrible and it was designed to be used with Windows, I don't think it will ever catch on with other systems.
>the concept is earthshattering powerful and the implementation is so simple
Yes, the concept is great, but I think the implementation leaves a lot to be desired. And while the implementation in theory is simple, the reality (bash) is much different.
Dozer · 2018-03-17 14:52
C
int y = x & -x;
Select lowest bit
Netrunner · 2018-03-17 15:36
>>7350
>rc still treats everything as strings and streams of bytes, so it is not such a huge improvement.
Treating all inputs and outputs as strings is exactly the point and what makes the unix pipeline so powerful.
>Now, Powershell definitely is a step in the right direction, but the UX is horrible
The reason ps is so horrible to use is because everything is an object instead of just text. So you need to introspect on data at every stage of the pipeline to figure out how to use it. Like everything ms does, ps is just a lame attempt to trap users into their walled garden ecosystem.
>the implementation in theory is simple, the reality (bash) is much different.
Bash is gnu and gnu is not unix.
Otto Normalverbraucher · 2018-03-17 22:43
To transpose a matrix with Scheme:
(apply map list matrix)
Unidentified · 2018-03-18 01:42
>>7356
>Treating all inputs and outputs as strings is exactly the point and what makes the unix pipeline so powerful.
This is a misguided argument. How often do you actually need to run operations that operate on streams of bytes on semi-structured data, and vice versa? And even in those cases, converting from structured data to stream of bytes would be trivial.
>So you need to introspect on data at every stage of the pipeline to figure out how to use it.
You need to do the same when dealing with semi-structured data in the unix shell, and you get none of the benefits that come with structured data, like completion or type checking. No, awk and tr ought to be enough for anybody.
BloodCat · 2018-03-18 12:10
>>7365
>This is a misguided argument. How often do you actually need to run operations that operate on streams of bytes on semi-structured data, and vice versa? And even in those cases, converting from structured data to stream of bytes would be trivial.
I don't even understand what you're arguing about anymore. If you don't like shell scripting then don't use it. I don't care, you're only crippling your own productivity.
string · 2018-03-18 16:16
>>7348
>You mean they did the simplest thing that works and then moved onto a more complicated approach as their requirements changed?
Exactly.
>The moral of the story is that Knuth wasted time and effort by doing an overengineered solution *first* and was then blown out of the water by a shell 1-liner which met the requirements just as well.
Come on. It's a column on literate programming Knuth was asked to write. He probably did everything himself to showcase the literate programming style. Then the Unix guy came and wrote some shell script that did the same thing. Yeah, everyone knows they can get soykaf done faster if they use libraries and tools. It's also a fact that high level explanations of problems are shorter than fhe ones that go over tiny details. That wasn't the point.
>>7356
>Treating all inputs and outputs as strings is exactly the point and what makes the unix pipeline so powerful.
Unix I/O isn't about strings, it's about bytes. Most output just happens to be encoded text, and terminals just happen to be able to render that text. You could just as easily make a terminal that could recognize and render PNGs when you catted them to standard output. It's all about the structure of the binary data.
>>7369
>I don't even understand what you're arguing about anymore
He's saying Unix I/O consists of the following phases:
>process encodes its internal data structures as human readable text
>process writes the text to file descriptor
>another process reads the text from file descriptor
>the other process decodes the data into internal data structures
There's a lot of parsing and serialization going on. Not only is there overhead with these operations, these codecs are often buggy ad-hoc implementations. It's well known that the vast majority of security critical bugs occur in the input handling sections of programs.
Nguoi La · 2018-03-18 16:52
>>7373
>Unix I/O isn't about strings, it's about bytes. Most output just happens to be encoded text, and terminals just happen to be able to render that text.
Humans understand text so programs output text. Having programs also take input as text lets you chain programs together in flexible ways. It's not rocket science.
>There's a lot of parsing and serialization going on...
The alternative?
Von Neumann · 2018-03-18 22:19
>>7374
>Having programs also take input as text lets you chain programs together in flexible ways.
You can pipe anything to any program. Nothing says you can't do things like:
download example.com/image.png | image-processor --convert-to-jpeg > image.jpeg
>The alternative?
Binary interfaces. Output data structures directly.
Cat Mother · 2018-03-19 00:07
>>7376
>Binary interfaces. Output data structures directly.
Then only programs that have been adapted to understand each others binary formats can be piped together. Isn't that a step backwards? Unlike text you can't just run a binary stream through awk.
Unspecified · 2018-03-19 21:11
>>7376
>You can pipe anything to any program. Nothing says you can't do things like:
Yes but binary interfaces are not at all flexible. Your example only works because png is a well specified file format.
>Binary interfaces. Output data structures directly.
The magic of Unix pipelines is sed, awk, tr, grep etc. let you mangle whatever text comes out of one program into the correct format for some unrelated program in the next stage of the pipeline.
Those who don't understand Unix are condemned to reinvent it, poorly.
Undisclosed · 2018-03-20 01:57
>>7376
Binary interfaces are never gonna fly, and if they take off it'd take decades for most tools to switch to them.
Also, they wouldn't be as flexible as treating everything as a stream of bytes.
What I had in mind was to reimplement all unix commands and most commonly used utilities in a hypothetical statically typed language designed for ease of writing and with primitives for dealing with unix, à la Scheme Shell, so that most commands would use the native data structures and be type-checked, and then make it easy to parse and serialize those data structures to arbitrary streams of bytes or inputs and outputs that can be understood by traditional programs as a light "ffi" mechanism.
>Those who don't understand Unix are condemned to reinvent it, poorly.
I hate this quote, because it seems to assume that Unix is some kind of peak of software engineering, and that nothing could ever surpass it.
You should go read the UNIX-Haters Handbook someday, it's old but still full of valid criticism. And try to understand what systemd and the other systems in modern linux that "do not adhere to the Unix philosophy" do that makes them better than what was used before, instead of whining about them.
⍕ · 2018-03-20 02:25
>>7356
>Bash is gnu and gnu is not unix.
>gnu is not unix
>is
You had one job.
Torvalds · 2018-03-20 18:20
>>7389
>You should go read the UNIX-Haters Handbook someday, it's old but still full of valid criticism.
Can you mention the points you find valid? I read it some time ago and I only remember agreeing with a single point or two.
Nguoi La · 2018-03-20 18:54
>>7389
>I hate this quote, because it seems to assume that Unix is some kind of peak of software engineering, and that nothing could ever surpass it.
No it doesn't. It means if you don't understand why things are done a certain way you are likely to repeat the same mistakes others have already made to get to where we are now.
>And try to understand what systemd and the other systems in modern linux that "do not adhere to the Unix philosophy" do that makes them better than what was used before, instead of whining about them.
Who is whining? You are the one projecting a strawman onto this quote and raging against unix for no apparent reason. Grind your ax somewhere else.
Switch · 2018-03-21 18:20
>>7377
Because awk tries to parse it as text. Text is binary data too. UTF-8, in particular, is a multibyte text encoding scheme.
>>7389
I don't want stuff to switch to binary. It's better to just leave the legacy alone. I'm just saying that it's all the same stuff at the end of the day. Text is still encoded to bytes, and the reason Unix programs have trouble with binary data is they try to decode the data as text even though it isn't text.
>What I had in mind was to reimplement all unix commands and most commonly used utilities in a hypothetical statically typed language designed for ease of writing and with primitives for dealing with unix, à la Scheme Shell, so that most commands would use the native data structures and be type-checked, and then make it easy to parse and serialize those data structures to arbitrary streams of bytes or inputs and outputs that can be understood by traditional programs as a light "ffi" mechanism.
Holy soykaf I have the same idea in my mind. I'm elaborating an optionally typed language specifically for Linux. I too share the dream of having all programs be written from scratch on top of a really good high-level programming language that can do anything. The core realization for me was that the Linux system call interface was actually language-agnostic -- you just need to put some values in the right registers and issue the system call. It's just like an FFI. A JIT compiler could easily do this and the languages would become powerful things... yet languages are implemented on top of C and its runtimes.
This project is taking me on an amazing journey, and is introducing me to some parts of the kernel code base. Did you guys know Linux exports its own headers as a user space API by sed'ing away the kernel-specific parts marked by a #ifdef __KERNEL__? There's a phony make target to install the headers by invoking a script that deletes all the stuff the kenrel doesn't want to share with user space before copying the files to /usr/include/linux.
I learned that most GNU core utils are mostly just wrappers over Linux system calls. The glibc people act like they own the Linux system call interface.
Pris · 2018-03-21 19:23
>>7403
>I don't want stuff to switch to binary. It's better to just leave the legacy alone. I'm just saying that it's all the same stuff at the end of the day. Text is still encoded to bytes, and the reason Unix programs have trouble with binary data is they try to decode the data as text even though it isn't text.
Are you the same retard who started that thread saying OO and FP is the same thing because it's compiled to machine code so there is no difference in the end? It's weird to see a programmer who is so insensitive to the concept of abstraction. Like a color blind painter to something.
Liet Kynes · 2018-03-21 19:39
>>7404
Or an illiterate novelist
Roy Batty · 2018-03-22 09:27
>>7404
>hurr retard what is abstraction
You're the moron talking about Unix as if it had "text interfaces" -- only someone who's barely scratched the surface of Unix and terminals would think that. The interfaces are all binary. I/O works in terms of bytes, not characters. It would have been useless otherwise. Programs call upon shared libraries through a binary interface. I am operating at the right level of abstraction.
The fact is a bunch of programs output and consume as input encoded text. They just assume the input is text and that you want text as output. If you give a picture to a program expecting text, it's probably going to corrupt the data. That's why git lets you specify binary files so that it won't try to do line ending conversion. If you output the picture to the terminal, it will probably screw up the terminal state.
Abstraction is what you make of those bytes. Text is NOT and CANNOT BE a universal abstraction.
Naomi Nascimento · 2018-03-22 09:45
>>7415
>You're the moron talking about Unix as if it had "text interfaces" -- only someone who's barely scratched the surface of Unix and terminals would think that.
I don't have anything new to say.
>>7384
>The magic of Unix pipelines is sed, awk, tr, grep etc. let you mangle whatever text comes out of one program into the correct format for some unrelated program in the next stage of the pipeline.
>Those who don't understand Unix are condemned to reinvent it, poorly.
> The interfaces are all binary. I/O works in terms of bytes, not characters. Programs call upon shared libraries through a binary interface. I am operating at the right level of abstraction.
>Computers process binary therefor everything is binary.
It's quite clear you don't understand abstraction at all.
if · 2018-03-22 10:04
>>7416
>>Computers process binary therefor everything is binary.
http://man7.org/linux/man-pages/man2/read.2.html
http://man7.org/linux/man-pages/man2/write.2.html
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
>read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf.
>write() writes up to count bytes from the buffer starting at buf to the file referred to by the file descriptor fd.
Drifter · 2018-03-22 10:46
>>7415
>You're the moron talking about computers as if it had "binary interfaces" -- only someone who's barely scratched the surface of computing and programming would think that. The interfaces are all ELECTRONS. I/O works in terms of ELECTRONS, not bytes or characters. It would have been useless otherwise. Programs read RAM and print to screen with ELECTRONS. I am operating at the right level of abstraction.
>Abstraction is what you make of those ELECTRONS. Text and binary is NOT and CANNOT BE a universal abstraction.
FTFY
Seriously dude, programming is not for you.
Incognito · 2018-03-22 12:33
>>7418
Don't be a try-hard. The fact is bytes are and have always been the correct level of abstraction for Unix-like systems. Text processing programs are found only in user space and there are other types of programs. Not all I/O is printable characters.
If you actually understood what Unix is all about, you'd know that the real killer feature is the pipe.
Drano · 2018-03-22 15:31
>>7403
>optionally typed
Into the trash it goes!
>yet languages are implemented on top of C and its runtimes
This is mostly to make a language easy to port to other kernels; FreeBSD and macOS have different syscall calling conventions from Linux and implement many syscalls differently, or not at all. Unix is a good enough layer of abstraction in most cases.
I think Go doesn't pass through C to do syscalls, so for example it doesn't support older version of macOS because some syscalls were deprecated in the newer versions.
>>7400
>It means if you don't understand why things are done a certain way you are likely to repeat the same mistakes others have already made to get to where we are now.
Except "where we are now" is not a great place, and the mindset of making things have a simple implementation to the detritement of interface and ease of use that comes with Unix is exactly what brought us here.
What I also hate about that quote is that it legitimizes the idea that if you don't like Unix you don't understand it. I absolutely understand it, I just think there could be better!
Cypher · 2018-03-22 16:14
>>7424
>Into the trash it goes!
Why? It seems optimum typing discipline for a scripting language. Allows you to write much shorter dynamically typed programs and scale up with explicit typing. It'd be a lot better than the literally untyped Unix shells.
You were talking about statically typed systems programming language, but then you mentioned scheme shell.
>This is mostly to make a language easy to port to other kernels
>FreeBSD and macOS have different syscall calling conventions from Linux and implement many syscalls differently, or not at all.
>Unix is a good enough layer of abstraction in most cases.
What does the system call entry point looks like on macOS and the BSDs? On Linux x86_64, all I have to do is put the function parameters in specific registers and use the syscall instruction.
It's true that the various Unix-likes differ a lot when it comes to non-POSIX functionality. A simple example is asynchronous I/O: POSIX has a bunch of old interfaces nobody uses anymore, Linux has epoll while the BSDs have kqueue. I don't care about supporting non-Linux systems very much, though.
>I think Go doesn't pass through C to do syscalls,
Indeed, Go appears to be an exception. It does have a syscall module. I haven't explored the Go implementation very deeply though. Last time I checked it out, I was more interested in Go's stack management, back when it used split stacks.
Do you know more details about this? Also, do you know if Rust depends on libc?
word · 2018-03-22 16:54
>>7424
Those who don't understand Unix are doomed to repeat it.
Nell · 2018-03-22 18:40
>>7426
Do you have any actual opinion or are you just going to keep repeating effect quotes?
swap · 2018-03-22 20:10
>>7425
>>Into the trash it goes!
>Why?
I just don't think optional typing is all that great. The underlying assumption is that it's more convenient to write programs without types, which I really don't think is true. With a flexible enough type system, good type inference and some kind of IDE-like functionality at the prompt that lets you resolve undecidable situations so you don't have to write any of the types yourself I think full typing would be viable.
>You were talking about statically typed systems programming language, but then you mentioned scheme shell.
Yeah, because to my knowledge it's the closest project that aims to replace shell scripting by exposing the syscalls rather than trying to embellish sh. I want something like that, just terse and with types.
>do you know if Rust depends on libc?
I don't think so, because I remember seeing libc among the things cargo downloads when I'm building alacritty and I'm too lazy to check right now.
It would also be pretty hypocritical to depend on libc, considering how the language has been marketed.
Splicer · 2018-03-22 20:40
>>7421
>If you actually understood what Unix is all about, you'd know that the real killer feature is the pipe.
Funny, because that's exactly what I said at the fuarrrking start.
>>7356
>Treating all inputs and outputs as strings is exactly the point and what makes the unix pipeline so powerful.
>>7421
>The fact is bytes are and have always been the correct level of abstraction for Unix-like systems.
Yes, strings are actually streams of bytes. Just like how bytes are actually streams of electrons. But that's got nothing to do with anything. Your inability to partition concepts into levels of abstraction is what led us down this retarded tangent.
>>7424
>What I also hate about that quote is that it legitimizes the idea that if you don't like Unix you don't understand it. I absolutely understand it, I just think there could be better!
Your strawman means whatever you want it to mean. That's what a strawman is.
Joey · 2018-03-22 22:03
>>7429
>Funny, because that's exactly what I said at the fuarrrking start
Then why are you so fixated on textual interfaces? You even quoted yourself:
>Treating all inputs and outputs as strings is exactly the point
Of course not, moron. The point is to pass data to another program directly. Hook up one program's output with another's input. The data itself doesn't matter.
>But that's got nothing to do with anything.
It has everything to do with everything, you dense motherfucker. Yes, all strings are bytes, but not all bytes are strings. Because Unix I/O works in terms of bytes, it can manipulate data that is more than encoded text and therefore is inherently more powerful than a textual interface.
Gyula Kovacs · 2018-03-22 22:32
>>7427
Here's an example of a man who doesn't understand unix.
Spike Spiegel · 2018-03-22 22:57
>>7433
I'm not the guy you are discussing with, but let me tell you're not very convincing.
You haven't given any argument to support your idea that input and outputs of programs should be strings, except for the fact that there are well known old programs dedicated to transform strings.
The fact is that obviously program can, and should sometime output binary format, like a program doing image processing, and there's nothing restraining the piping of images though different programs.
The only reason strings were historically prefered is that they are easily human writable and readable.
But of course we now have formats like json that describe a binary object through a string. I don't see any reason why you couldn't build tools dedicated to work with json objects instead of strings (and have you noticed ? you can encode binary objects with strings ! which means strings are binary, and binary are strings ! )
word · 2018-03-23 21:40
>>7431
>Then why are you so fixated on textual interfaces?
Already answered in >>7384
>The magic of Unix pipelines is sed, awk, tr, grep etc. let you mangle whatever text comes out of one program into the correct format for some unrelated program in the next stage of the pipeline.
>>7431
>Of course not, moron. The point is to pass data to another program directly. Hook up one program's output with another's input. The data itself doesn't matter.
Already answered in >>7384
>Yes but binary interfaces are not at all flexible. Your example only works because png is a well specified file format.
>It has everything to do with everything, you dense motherfucker. Yes, all strings are bytes, but not all bytes are strings. Because Unix I/O works in terms of bytes, it can manipulate data that is more than encoded text and therefore is inherently more powerful than a textual interface.
I understand how strongly you feel about "Unix I/O" but it's not relevant to the discussion. Stop it already.
>>7436
>You haven't given any argument to support your idea that input and outputs of programs should be strings, except for the fact that there are well known old programs dedicated to transform strings.
Read it again >>7384
>The magic of Unix pipelines is sed, awk, tr, grep etc. let you mangle whatever text comes out of one program into the correct format for some unrelated program in the next stage of the pipeline.
If you're not convinced that's your problem. Those who don't understand Unix are condemned to reinvent it, poorly.
>The fact is that obviously program can, and should sometime output binary format, like a program doing image processing, and there's nothing restraining the piping of images though different programs.
What's stopping you is that other programs need to be hardcoded to understand the binary format. And when the binary format changes, all programs need to be updated and recompiled. String based interfaces don't have this problem because awk/sed/etc. can act as glue. So in practice the only programs that operate on binary files are well specified universal formats like images and videos.
>The only reason strings were historically prefered is that they are easily human writable and readable.
Wrong. >>7384
>The magic of Unix pipelines is sed, awk, tr, grep etc. let you mangle whatever text comes out of one program into the correct format for some unrelated program in the next stage of the pipeline.
>But of course we now have formats like json that describe a binary object through a string. I don't see any reason why you couldn't build tools dedicated to work with json objects instead of strings (and have you noticed ? you can encode binary objects with strings ! which means strings are binary, and binary are strings ! )
I don't understand your point. Blobs can be encoded into ascii characters like base64 but you still can't mutate them in any flexible or meaningful way. You might be interested to know that the FreeBSD project started adding json output to their base system utilities though.
Liet Kynes · 2018-03-23 21:53
>>7446
an example of somebody who understands unix better than most people who bs'd their way through this thread
Roy Batty · 2018-03-23 21:54
>Treating all inputs and outputs as strings is exactly the point
I think I see the confusion.
Person A is emphasizing the ALL part, as if Unix pipes filter out non-ascii characters or something which is obviously wrong.
Person B is emphasizing the TREATING part, programs *choose* to deal with strings because they are flexible.
A combination of poor phrasing from Person B and bad faith from Person A is what lead to this soykafty derailment. Can you guys stfu now?
Turing · 2018-03-23 21:57
>>7448
It doesn't even matter that programs deal with "strings" by default, most modern implementations allow you to specify bytes, strings, etc.
The Linux kernel itself runs sed on binaries to make edits for fuarrrk sakes.
Just drop the "muh strings" horsesoykaf, it's false and wrong.
St. IGNUcius · 2018-03-23 22:43
>>7449
>It doesn't even matter that programs deal with "strings" by default, most modern implementations allow you to specify bytes, strings, etc.
>Just drop the "muh strings" horsesoykaf, it's false and wrong.
Did you even read the post you are responding to? You keep trying to convince Person B that Unix pipes can handle binary data. Stop arguing in such bad faith and reread Person B's posts assuming he already knows that.
>The Linux kernel itself runs sed on binaries to make edits for fuarrrk sakes.
That sounds easy to prove.
$ cd /usr/src/linux
$ grep -rP '\| sed\b'
Copy and paste the one you mean.
quote · 2018-03-24 00:06
>>7451
Unix pipes handle binary data just fine.
tar c binaryFile | gzip > binaries.tar.gz
Get your head out of your arse.
Arisu Mizuki · 2018-03-24 00:07
>>7453
Let's not forget other examples
dd if=/dev/sda | xz > diskImage.xz
array · 2018-03-24 00:42
This is an excerpt from The UNIX-HATERS Handbook, chapter 6, Terminal Insanity; this is relevant in the current discussion as an example of how strings are not, in fact, equivalent to binary data, at least as far as UNIX is concerned:
This state of affairs, like institutionalized bureaucracies, would be livable
(though still not acceptable) if there were a workaround. Unix offers no
workaround, indeed, it gets in the way by randomly permuting control
commands that are sent to the VDT. A program that wants to manipulate
the cursor directly must go through more gyrations than an Olympic gym-
nast.
For example, suppose that a program places a cursor at location (x, y) by
sending an escape sequence followed by the binary encodings of x and y.
Unix won’t allow arbitrary binary values to be sent unscathed to the termi-
nal. The GNU Termcap documentation describes the problem and the
workaround:
Parameters encoded with ‘%.’ encoding can generate null charac-
ters, tabs or newlines. These might cause trouble: the null character
because tputs would think that was the end of the string, the tab
because the kernel or other software might expand it into spaces, and
the newline because the kernel might add a carriage-return, or pad-
ding characters normally used for a newline. To prevent such prob-
lems, tgoto is careful to avoid these characters. Here is how this
works: if the target cursor position value is such as to cause a prob-
lem (that is to say, zero, nine or ten), tgoto increments it by one, then
compensates by appending a string to move the cursor back or up
one position.
Alan Bawden has this to say about the situation:
Date: Wed, 13 Nov 91 14:47:50 EST
From: Alan Bawden <Alan@lcs.mit.edu>
To: UNIX-HATERS
Subject: Don’t tell me about curses
What this is saying is so brain damaged it brings tears to my eyes. On
the one hand, Unix requires every program to manually generate the
escape sequences necessary to drive the user’s terminal, and then on
the other hand Unix makes it hard to send them. It’s like going to a
restaurant without a liquor license where you have to bring your own
beer, and then the restaurant gives you a dribble-glass to drink it
from.
Demeere · 2018-03-25 05:57
For any C newbies: a stream of bytes and a string differ in only one way: a string is always null terminated. Otherwise, they are both streams of bytes.
When reading from a pipe (which is exactly the same as reading from a file) you are reading a stream of bytes that could also be a string, but not necessarily.
It doesn't matter, though, because read's are always EOF terminated (handled by `read' itself).
So, yeah, piping data is no different than reading streams of bytes (which do not need to be null terminated). But if you want to parse that data, it must be a rigid format. What happens if you want to read in data that can be of any size and also there can be multiple 'datums'? The easiest rigid format for that is just appending a null character to say 'hey, you're done with this particular datum.'
Mario Rossi · 2018-03-25 14:43
>>7465
>The easiest rigid format for that is just appending a null character to say 'hey, you're done with this particular datum.'
It's also easy to prefix data with its size. The program would then read the size first, then predict that there will be exactly that many bytes coming in as input.
The advantage is the size is always known and fixed, and determining it doesn't require scanning through the data loooking for a sentinel, an operation which will loop infinitely if it is not actually there. There can also contain NUL bytes as part of the data itself and it won't affect the program in any way since it will always read an exact amount of bytes.
Yet Another Lainon · 2018-03-27 19:07
>>7356
>Treating all inputs and outputs as strings is exactly the point and what makes the unix pipeline so powerful.
Unix tools treat everything as lines. They are line-oriented. It means they will split input at every line feed into a list of logical lines and treat these lines as the quantum of computation. It doesn't really matter if the data contained in the string is printable ASCII or UTF-8 code points or structured or even random binary data, it's still going to get split into chunks at whatever hard-coded byte the program considers to be the line feed character.
It's a simple tokenizing technique. The most obvious result of tokenization is the dramatic reduction in the number of input symbols, and we see it happening with line-oriented tools: what was once a huge stream of individual bytes becomes a much smaller list of lines. And thus we have programs that operate on these lines, and it doesn't get more complex or powerful than that.
There are more powerful paradigms out there. Rob Pike wrote about one and it is currently reified as the sam and vis editors, which are notably byte oriented and can edit binary streams just as easily as encoded text. It's interesting because it's just as simple as the traditional tools but supports a greater linguistic complexity than the one afforded by the line-oriented tokenization process.
We're still far from the ideal of painless and composable context-free parsing, to say nothing of context-sensitive grammars which is the case of many binary data formats.
Void · 2018-04-26 16:41
test.c
const int main[] = {
1214185834,931213,208273408,
267946330,1795109125,84891708,
1819043144,1867980911,560229490
}; gcc -o hello test.c
try it for ya self
Bobby Tables · 2018-04-30 21:33
If someone wants to generate nth Fibonacci number in an esoteric way:
#include <stdint.h>
#define GOLDEN_RATIO 1.6180339887498948
#define INV_GOLDEN_RATIO 0.6180339887498948
#define INV_SQRT_5 0.4472135954999579
#define loop(n) for (uint32_t _=0; _<(n); _++)
double fibonacci(const uint32_t * n){
if (*n == 0) return 0.;
if (*n == 1) return 1.;
double gr_n = GOLDEN_RATIO,
inv_gr_n = INV_GOLDEN_RATIO;
float casted_n = *n;
uint8_t log2n = (*(uint32_t*)(&casted_n) >> 23) - 127;
loop(log2n) {
gr_n *= gr_n;
inv_gr_n *= inv_gr_n;
}
loop(*n-(1u<<log2n)) {
gr_n *= GOLDEN_RATIO;
inv_gr_n *= INV_GOLDEN_RATIO;
}
return INV_SQRT_5 * (gr_n - inv_gr_n);
}
Above soykaf contains matrix diagonalization and IEEE 754 bithacks to limit number of floating-point operations. It should have O(log(n)) complexity.
Jens Hansen · 2018-04-30 23:49
>>579
/bin/mksh: sed not found
John Peters, You Know, the Farmer · 2018-05-19 19:45
Here's some code I cooked up this morning. I've always wanted a way to create a spiral that'd be easy for me to remember.
The basic idea is that drawing a spiral is nothing more than drawing a bunch of concentric rectangles (with you changing the number you're placing at each step), so if you have a code that can do one rectangle of numbers, extending it to make a spiral isn't too much more difficult.
Anyway, here's the code (C99, Uses VLA's... Not really sure how I would do this one with pointers, to be honest)
void
createSpiral(int nRows, int nCols, int matrix[nRows][nCols])
{
int start = 1;
int offset = 0;
while(offset <= nRows/2)
{
start = createInnerSpiral(nRows, nCols, offset++, start, matrix);
}
}
int
createInnerSpiral(int nRows, int nCols, int offset, int start, int matrix[nRows][nCols])
{
int cInd, rInd;
int counter = start;
//Create top row
for( cInd = offset; cInd < nCols-offset; cInd++, counter++)
matrix[offset][cInd] = counter;
//Create rightmost column (going down)
for(rInd= 1+offset; rInd < nRows-offset-1; rInd++, counter++)
matrix[rInd][nCols - 1-offset] = counter;
//Create bottom row
for(cInd = nCols-1-offset; cInd >= offset+1; cInd--, counter++)
matrix[nRows-1-offset][cInd] = counter;
//Create leftmost column (going up)
for(rInd = nRows-1-offset; rInd >= 1+offset; rInd--, counter++)
matrix[rInd][offset] = counter;
return counter;
}
By the way, not entirely sure this works for *every* case, but I've tested it for a couple of cases and it seems to work just fine. Suggestions are always welcome!
Dor · 2018-05-20 00:11
>>434
dont use this if you cant guarantee that a and b are different
Zhora · 2018-05-20 09:50
>>8110
It's a little weird though that the function returns a double.
Crash Override · 2018-05-27 22:20
>>7320
Even though i really like shellscripting and McIlroy,
I cannot but disagree with this critique of Knuth:
Knuth was not simply writing a program most fit to a certain, fictional purpose,
he wrote a program that, despite of the simple objective,
showcased a specific style of coding, a style that seems pretty swell in my opinion.
Frank Garza · 2018-05-29 12:47
>>8111
sudo pacman -S coreutils
pop · 2018-05-30 02:44
>>434
Out of curiosity, I wanted to see how typical swap compares when the temp variable is declared with the register keyword. It saves just a touch of size and two operations.
Joey · 2018-05-31 16:00
>>8372
I just tested this, and this does work when a and b are different.
//Using a == b
a = a XOR b; //a now equals zero
b = a XOR b; //b now equals b (anything XOR'ed with zero is itself)
a = a XOR b // a now equals b, which equals a
Batou · 2018-05-31 18:31
>>8470
Interesting. Did you compile with -O2? I was told that the register keyword is obsolete because the compiler always knows how to optimize the better.
Ivan Petrov · 2018-06-13 12:02
I've written a short test that swaps the value of two registers 10 billion times, and there was no difference in speed on my processor: ~/g/asm$ time ./swapXOR.elf
real 0m12.743s
user 0m12.730s sys 0m0.000s
~/g/asm$ time ./swapXOR.elf
real 0m12.736s
user 0m12.720s
sys 0m0.010s
~/g/asm$ time ./swapTempVar.elf
real 0m12.741s
user 0m12.730s
sys 0m0.000s
~/g/asm$ time ./swapTempVar.elf
real 0m12.736s
user 0m12.720s
sys 0m0.000s
Yu-ichi · 2018-06-13 22:09
>>8900
have you tried using xchg?
Bobby Newmark · 2018-06-15 10:41
>>8905
I don't have an x86 chip handy atm, and ARMv8A CPUs like my phone's don't have an xchg instruction. But I did a test to see how using main memory instead of a spare register affects speed, and the test ran between 15% and 20% slower than either of the other algorithms. On a cpu that doesn't have a cache, you can expect a much bigger hit to performance.
So yeah, I haven't done any tests on how it affects speed in a real program where the ALU is needed by other instructions in the pipeline, but so far it seems the xor trick is definitely what you'd want to use for an assembler macro on ARM, like "swapRegs reg1, reg2" or so. No need for a spare register, no need to use slow main memory.
Trinity · 2018-07-28 00:27
if ( s.balance < 0 )
{ p.balance = 1;
node.balance = 0;
} else if ( s.balance == 0 )
{ p.balance = 0;
node.balance = 0;
} else
{ p.balance = 0;
node.balance = -1;
}
Some example code I saw in a shady corner of the net, where some heretic profaned all the virtues of curly brace alignment... to align the curly braces!
Absolutely diksukthings.
It's just so wrong. I think I'll start using this style now.
Naomi Nascimento · 2018-09-20 00:04
>>1596
Does it support some small subset of J or it's a full-fledged interpreter?
Unspecified · 2018-09-20 14:34
>>7289
And it was already posted and discussed in this thread?
FILLER · 2018-10-11 14:26
Maybe this one's a bit too much of a "toy" for this thread, but I thought it was neat.
A two-to-three line implementation of fizzbuzz (depending on where you start counting).
const char* strings[4] = {"%d\n", "Fizz\n", "Buzz\n", "FizzBuzz\n"};
for(int i = 0; i < MAX_NUM; i++ )
printf(strings[((i % 3) == 0) + 2*((i % 5) == 0)], i);
How it works: The equality operator returns 0 on failure and 1 on success, which means we can encode 2^n different values, where n is the number of conditions we have.
According to the standard, if the format string is done before the argument list is, then the rest of the arguments are evaluated but not printed. In this case, that means any time we don't use a "%d", we just 'throw the argument out' per se.
So if you're ever asked to write fizzbuzz (or more generally, encode information without if statements), here you go!
DavidGaβrieλ · 2018-10-12 20:41
>>578
Now I get it. Nice bro it is `A E S T H T I C`
DavidGaβrieλ · 2018-10-12 21:06
>>1663
I wish I could Understand Lisp macros well. I feel dump
>>3385
This is Cpp code, not a C code right ?
Eldon Tyrell · 2018-10-13 04:14
>>10882
It looks like C to me
The Fin · 2018-10-24 22:31
C
#include <stdio.h>
#define calculate(...) \
calculate_f((calculate_s) { .a=1, .b=1, .total=0, __VA_ARGS__})
typedef struct {
int a;
int b;
int total;
} calculate_s;
int calculate_f(calculate_s t)
{
return t.total + t.a * t.b;
}
int main()
{
printf("%d\n", calculate(.a=12));
printf("%d\n", calculate(.b=10, .total=10));
return 0;
}
dictionary · 2018-10-27 14:58
>>430
Any reason to use an enum instead of an int here?
Drifter · 2018-12-26 01:24
>>3367
Make that a case statement >:(
Eldon Tyrell · 2018-12-26 01:25
>>11091
Thats beautiful.
I love this use of structs.
Concise C is so pretty.
The Oracle · 2018-12-26 01:51
>>7243
bullsoykaf its "i work in a senior dev team" vs "I write code that interns use"
Junichi Fujiwara · 2018-12-26 17:55
>>11880
You can do case statements on ranges of doubles? Or do you mean multiplying it by four, rounding it to an int and switching off that?
Otto Normalverbraucher · 2018-12-28 02:05
i dunno if it is all that aesthetic but here is a snippet I wrote for Easier68k, a crossplatform Motorola 68k assembler.
python
def assemble(self) -> bytearray:
"""
Assembles opcode into Hex
:return: Hex for this operation
"""
assert self.cond_code != None
extraSize = 2
self.offset = self.operand
self.offset = Bits(int=self.offset, size=self.size)
# clear for >8 bit offset
lastbyte = '\x00'
# if offset is 8 bits than it is inside the opword
if self.size == OpSize.BYTE:
lastbyte = self.offset.to_bytes()
extraSize = 0
# if offset is 32 bits than the last chunk of opword is FF
if self.size == OpSize.LONG:
lastbyte = '\xFF'
extraSize = 4
# first byte = 6+cond_code
firstbyte = 6 << 4
firstbyte &= self.cond_code.to_bytes()
opword = firstbyte << 8
opword &= lastbyte
opword = bytearray(opword.to_bytes(2, 'big'))
# stop here if 8 bit offset
if self.size == OpSize.BYTE:
return opword
# add offset
opword.extend(self.offset.to_bytes(extraSize, "big"))
return opword
Turner · 2018-12-28 10:55
>>11895
Why does this need to be a method
The Plague · 2018-12-28 12:25
>>11895
>lastbyte = '\x00'
>lastbyte = '\xFF'
>opword &= lastbyte
>TypeError: unsupported operand type(s) for &=: 'int' and 'str'
Marly Krushkhova · 2018-12-28 20:46
>>11899
each opcode has its own class with an assemble method. I did not design this.
>>11901
Shortly after I posted this I changed the and to an or and casted the byte to an ordinal.
BloodCat · 2018-12-31 02:28
>>7320
You say that but I bet you can't find a single bug in the TeX source code.
Elliot Alderson · 2018-12-31 02:43
>>7376
>> The alternative?
> Binary interfaces. Output data structures directly.
Ok. So my program output a list of maps. Another program still has to read that in, correct for errors in transmission, etc. I guess you could output memory locations with a typed structure that is given as stdargs and owned by the shell (because otherwise it's lost on program death). That would be interesting but I sense a number of problems with it. The one that comes to mind at the moment is, ultimately at some level, it needs to output text because humans understand text. Not to mention the potential security problems involved, and it would either be utterly restrictive or would need support for plugging in custom data structures, and you are basically back to square one...
quote · 2018-12-31 02:49
>>7390
>>gnu is not unix
>>is
>
>You had one job.
> 2018
> Not understanding how contractions work
cond · 2018-12-31 11:55
>>7242
I find myself subtly annoyed by this.
Anyway to save the bother for anyone else, fake tweet never happened.
Mentat · 2019-01-02 12:44
Spike Spiegel · 2019-01-02 13:18
>>436
>>434
>>443
>>436
>>446
>>447
>>448
A nice way to think about it is that bitmasks (of equal size) form a Boolean Ring (wikipedia.org/wiki/Boolean_ring)
That is, a structure where you can add and multiply (holding associative, commutative, etc laws).
Here multiplication is AND and addition is XOR.
Bitmasks are basically subsets of a set comprised of as many elements as bits on the bitmask. AND is set intersection, and XOR is symmetric difference (wikipedia.org/wiki/Symmetric_difference).
It's a clerk-tier job to check that all Ring properties hold when you define multiplication as AND/intersection and addition as XOR/symDiff (eg. show that 1111... is the multiplicative identity)
What >>447 said would read as "0000... is the additive identity" and "bitmasks form a Boolean ring" (ie. a + a = 0)
After that, you just read the code as a way of saying:
a2 = (a + b) + (b + (a + b))
b2 = b + (a + b)
Leaving the final values:
a2 = b
b2 = a
Which is an easy way to realise the original values of a and b don't matter at all (>>8517 >>8372)
Unspecified · 2019-02-26 09:56
There are some really nice code features I am really fond of and would include in my ideal language, here is some psuedo code:
F(N) = N + 5
F(6) = 3
I think you can do this in Haskell, overriding the function for a specific parameter. Beautiful!
Short circuit conditional statements :
(x==1 and f()) or (x==2 and g()) or (true and h())
See link, I think this link is a good all round read: https://developer.ibm.com/articles/l-prog/
The Fin · 2019-02-26 20:56
>>12698
>I think you can do this in Haskell
you would be correct. now go learn haskell and make the world better for all of us.
Hiro Protagonist · 2019-03-02 00:05
>>7389
>so that most commands would use the native data structures and be type-checked, and then make it easy to parse and serialize those data structures to arbitrary streams of bytes
I want to understand this better, so we could have a program output a linked list and pipe it into another that handles linked lists? What would be the differences in
find . -name "*.html" | wc -l ?
Donna Hawthorne · 2019-03-02 20:46
Heres a neat operation for when you need a list as a result of a tree traversal.
This example is for interspersing commas in a string, but works for stuff like {pre,in,post}order tree traversals too, and looks real fun
Faster than using ++ too
join' :: [Char] -> ([Char] -> [Char])
join' (x:xs) = (x:) . dropLast . (join' xs)
where
dropLast = if (xs /= []) then (',':) else (id)
join' [] = id
answer :: [Char] -> [Char]
answer x = join' x $ []
Aristóteles Amadópulus · 2019-03-04 02:59
>>8032
when i compile this without optimization (-O0) and look at the output of "objdump -d hello", there is no <main> function.
can anyone explain why?
Shogun · 2019-03-05 06:25
>>12748
Try with -D
Dujour · 2019-04-12 11:36
>>> import itertools
>>> for k in itertools.chain.from_iterable (itertools.repeat (itertools.islice (itertools.cycle ((0, 1)), 5))):
... print ("lain", k)
...
stack · 2019-04-14 20:43
>>12698
pattern matching
This is one of the big reasons I am finding it hard to go back to imperative languages after Haskell.
DEBUG-CONTENTS · 2019-12-24 01:51
To bump this thread, I'll mention some APL I wrote recently and shared in the APL thread: >>15664
This is the Rule 30 cellular automaton in one line of APL:
N←(1 1,~N)=(0,N,0)∨N,0 0 Here, N is a simple bit vector and is assigned the next generation. You'll notice that the code resembles the truth table for the automaton, even in layout, and the left case is nicely distinguished by optimizing the NOT of two zeroes into simple literal ones. There's more information in the APL thread, for those curious.
Chani · 2019-12-24 12:16
>>7241
Apparently the bash source code is littered all over the place with this cursed macros
Dozer · 2019-12-27 00:13
>>7241
You're going to have a hard time learning Lisp or Scheme.
bit · 2019-12-27 00:22
>>3353
I use partial application of function extensively in Python
from functools import partial
def multiply(a, b):
return a * b
twice = partial(multiply, 2)
>>>print(twice(5))
10
The Oracle · 2019-12-28 16:45
>>16316
lambdas are still a thing, too
def multiplier(factor):
return lambda number: number * factor
twice = multiplier(2)
print(twice(5))
cond · 2019-12-28 18:29
>>16315
No, macros in Lisp are hygienic and not disgusting.
Zuse · 2019-12-28 19:35
>>16296
The Linux kernel uses something similar for linked lists.
Cypher · 2019-12-29 01:44
>>16328
Thing is, you can use partial all around.
from functools import partial
class Connection:
def __init__(self, addr, port, proxy_host=None, proxy_port=None, proxy_auth=None):
...
proxied_connection = partial(Connection, proxy_host="1.2.3.4", proxy_port=1234, proxy_auth=('hello', 'world'))
proxied_connection("google.com", 80)
You don't have to prepare the function for it to work as partially applied, and you can easily pass kwargs. If that were a "div" function instead, you could have done that easily:
from functools import partial
def division(a, b):
return a / b
divided_by_two = partial(division, b=2)
divided_by_four = partial(division, b=4)
two_divided_by = partial(division, 2)
Sometimes, partial won't cut it, and lambda will be more useful, for minimal processing of args or more clever reordering. In any case.
>>>print(twice(5))
10
J.C. Denton · 2020-01-02 11:05
>>13230
Rust has pattern matching, it has algebraic types (think product type, sum type as in category theory / ocaml style) built in. I was mostly a ocaml programmer for everything including work, but since I have discovered Rust I only use it. I don't know other languages with pattern matching that aren't functional languages or ML style languages.
Chani · 2020-01-02 13:41
>>16410
D has it as well in sumtype library: https://github.com/pbackus/sumtype
and of course C++ has it as well. Though std::variant is relatively poor (in terms of efficiency), but there are better third-party libraries apparently. It's almost impossible to find an example use of std::variant that shows off ML-style pattern matching instead of using it like an int-or-string-or-float type safe union. It really comes cross that C++ people don't really understand what the feature is for.
>other languages with pattern matching that aren't ... ML style languages
but that's what Rust is. Immutable as the default, ML datatypes, pattern matching as a routine feature but not in function heads like Erlang or Haskell, error handling with optional types. Rust just removes exceptions and GC. Rust strikes me as more an ML than a C++-like language when it doesn't even have C++-style templates.
Another language without a GC and with lots of non-ML influence (exact C types, semantics, and performance) is ATS, but that's a lot less baked, and it still has exceptions.
Unspecified · 2020-01-03 20:36
>>430
J
sign_repr =: <;._1 '/something weird/sign and magnitude/one''s complement/two''s complement'
sign_repr {~ _1 (17 b.) 3
┌────────────────┐
│two's complement│
└────────────────┘
Pris · 2020-01-27 22:49
>>434
What about this does it have some cases where it's wrong
a= a+b ;
b=a-b;
a=a-b;
Crash Override · 2020-01-27 23:41
>>7347
Agreed. I want to try this at some point this: https://scsh.net. Or write my own OS that's all Scheme from the ground up (Holy Scheme maybe?).
Ein · 2020-01-30 19:21
>>16695
I think the only drawback is that a+b might overflow, while xoring would not.
>>16696
There's also ipython ( https://ipython.readthedocs.io/en/stable/interactive/shell.html ) that could be used as a shell replacement. I have not tried it like that though.
McCarthy · 2020-02-02 01:41
>>16695
Technically, it is undefined behavior if a+b overflow.
You could get the wrong answer if a+b overflow & either of the following:
1. the computer uses a weird signed int representation
2. the compiler optimizes
Neither of these are very likely for the average person,
so realistically you would get the same result even if it does overflow.
Neo · 2020-02-02 23:24
shuffle in J:
({~ ?~@#) 1 1 0 2 3
2 0 3 1 1
({~ ?~@#) 1 1 0 2 3
1 1 2 0 3 this works by generating a random list of indexes and then fetching them from the to-be-shuffled list.
This code has three verbs:
# 5 5 5 NB. monadic tally: get number of elements in list
3
3 ? 5 NB. dyadic deal: pick 3 items from [0,5) at random, without repetition
0 2 3
3 ? 5
0 3 2
1 { 2 3 NB. dyadic from: an array index. [2,3]->[1]
3
0 { 2 3
2
(0 1) { 2 3 NB. it works with multiple indexes too
2 3
(1 1) { 2 3
3 3
(1 0 1 0) { 2 3
3 2 3 2 and then an adverb ~, a conjunction @, and an 'invisible conjunction' (hook).
2 3 {~ 1 NB. dyadic from with args swapped.
3
2 3 {~ 0
2
?~ 3 NB. dyadic deal with y as both args
2 1 0
?~ 3
2 0 1
?~ 3
1 2 0
3 ? 3
2 1 0
(?~@#) 1 1 1 NB. (?~ (# 1 1 1)), ?~ applied to #'s result
2 0 1
(?~@#) 1 1 1
1 0 2
(?~@#) 1 1 1
1 0 2
({~ ?~@#) 5 0 2 NB. a hook: (f g) y <-> y f g y
5 2 0
({~ ?~@#) 5 0 2
0 2 5
5 0 2 {~ (?~ (# 5 0 2))
0 5 2
5 0 2 {~ (?~ (# 5 0 2))
2 5 0
5 0 2 {~ (?~ (# 5 0 2))
2 0 5 despite all this analysis, this is pretty simple code and only a few weeks of J would be enough to read it comfortably. The key insight is using dyadic ? to generate random indexes. With that hint even a brand new J programmer should come up with something like
shuf =: 3 : '((#y) ? #y) { y'
shuf 6 5 5 5 0 4
5 4 5 6 0 5
shuf 6 5 5 5 0 4
4 5 6 5 0 5
roll · 2020-02-12 04:46
>>16337
That's kinda sexy
Guthrie · 2020-02-14 06:44
>>16856
How is this any better than lambda expressions?
They're about equally complex, but infinitely more flexible.
proxied_connection = lambda args: Connection(*args, proxy_host="1.2.3.4", proxy_port=1234, proxy_auth=('hello', 'world'))
proxied_connection("google.com", 80)
I get that you have to write "args" twice this way, but saving two words isn't that sexy, it?
Is there something i'm missing?
Hitomi · 2020-02-18 21:37
>>3288
#include <stdio.h>
int main()
{
int arr[] = {1, 2, 3};
{
size_t i = 0, element_count = sizeof(arr) / sizeof(*arr);
goto PRINT_ELEMENT;
PRINT_COMA:
putchar(',');
PRINT_ELEMENT:
printf("%d", arr[i]);
if (++i == element_count)
goto END;
goto PRINT_COMA;
END:;
}
putchar('\n');
return 0;
}
John Doe · 2020-02-19 22:24
>>16906
Lambdas in python suck hard, since they can only contain a single expression.
Also I'm really not sure your example works, as host and port are passed twice, one as a positional argument, and then as a named argument.
Python is not very good for functional progaming, and that's a shame.
Jane Doe · 2020-02-20 00:14
>>3353
>The "freezing" of chunks of code is rad.
In Haskell, this is the default behavior. Any function called with less arguments than it takes will return a function that takes the remaining arguments.
>>16906
>How is this any better than lambda expressions?
You can replace all code with lambdas. The intermediate representation of many compilers is a giant clump of lambdas.
The point of functions like 'partial', 'compose', and 'on' is that they give names to common patterns.
>Also I'm really not sure your example works, as host and port are passed twice, one as a positional argument, and then as a named argument.
They are not passed twice. There is a a positional host argument and a positional port argument. There is a named proxy host argument and a named proxy port argument. The arguments do not overlap.
Stallman · 2020-02-24 03:48
It blew my mind when i discovered you could implement stacks with a single pointer in C.
int stackdata[1024];
int *stackptr = stackdata - 1;
/* PUSH */
*++stackptr = 1;
/* POP */
stackptr--;
/* PEEK */
*stackptr;
Wirth · 2020-02-27 03:59
>>16953
>goto
>goto
>goto
Yikes. Throw that trash out and start over.
Lady 3Jane.. · 2020-02-27 15:21
>>16330
Common Lisp macros are not hygienic.
Drano · 2020-02-27 16:51
>>17019
What if one wants to increase the size of the stack without having to worry about free() and malloc()?
Chan Siu Ming · 2020-02-28 11:06
>>17139
realloc()
Also, if you want speed, you really don't want reallocations, just allocate what you need.
Neo · 2020-03-05 15:18
>>17128
gotos are closer to assembly
Jane Doe · 2020-03-06 06:40
>>17230
Assembly isn't C, and C isn't assembly. See the problem?
string · 2020-03-06 07:59
>>17150
>realloc()
... has the same or worse performance as malloc(). Its best case is an extension, worst case is a new malloc followed by a copy.
Leto Atreides I · 2020-03-06 08:27
>>17238
yeah? I don't understand your point, everyone knows reallocating is slow
Bobby Newmark · 2020-03-07 09:34
AESTHETIC?
More like hard to read / understand if you work in real world conditions in a team. If you do one of those things posted here in a real project you would get fired.
Code is for human to easily read and understand without retrying and figuring out what the heck is going on there.
Just because you can do something like this doesn't mean you should do it.
And when you try to squeeze out performance then directly do it in ASM, no one holds you back there.
As a fun showing of what's possible is no problem of course, but keep in mind that you NEVER EVER should do it in real projects. You WILL lose your job (rightfully).
Turner · 2020-03-07 09:36
>>17128
Totally legit element. Just you learn in school that you never should use goto doesn't mean you really shouldn't if you actually know what you are doing.
In really low level system coding in C you actually can't get around goto. For example search in the Linux kernel (or any other). You will find thousands of gotos.
array · 2020-03-07 10:44
>>572
Does declaring a string literal with const prevent set faults errors when trying to modify it? I think the compiler should give you a warning iirc. My C is a bit rusty and I don't remember those sort of caveats very well.
Mitnick · 2020-03-07 17:31
>>17248
This is horseshit. If you structure your code correctly, you never need a goto. Being in the linux kernel doesn't make it legitimate. And no, as somebody who does low level programming, what you're saying about it being "impossible" to get around is simply untrue.
Unspecified · 2020-03-07 21:03
>>17251
>you never need a goto
>you never need a goto even if a language has no function/subroutine/return/class/method/macro but has goto
hmmmm.
[X] Doubt.
Agreed that a goto is usually a symptom of poor code structure.
Mentat · 2020-03-07 22:03
>>17255
>no function/subroutine/return/class/method/macro
We're not talking about such a language, but thanks for moving the goal posts.
Lunch · 2020-08-19 10:10
I am surprised no one mentioned the Obfuscated C Contest: https://ioccc.org/
It is the oposite of aesthetic, however, there are some really clever tricks/snippets that can be used in aesthetic C.
Also, bump. I think this thread can give a bit more to the community.
Koos van der Merwe · 2020-08-19 11:28
>>17251
Goto is never needed to jump backwards, but forwards is totally ok. Like leaving a nested loop or handeling errors.
Church · 2020-08-19 13:05
>>20370
>thread about aesthetic code
>post obfuscated C contest
What did he mean by this?
Neuromancer · 2020-08-23 15:23
>>16953
>>17251
>>17128
csv printing with the least amount of branching uses goto, but it can be done with just one which is much cleaner.
#include <stdio.h>
int main(){
int arr[] = {1, 2, 3};
size_t i = 0, element_count = sizeof(arr) / sizeof(*arr);
PRINT_FIELD:
printf("%d", arr[i]);
if (++i < element_count){
putchar(',');
goto PRINT_FIELD;
}
putchar('\n');
return 0;
}
Jim Hilger · 2020-08-23 17:57
>>16953
>>20418
>not properly handling empty array case
>two printf/putchar function calls most iterations when you can do with just one
>thinking this even needs goto to minimize branching
shameful display
C
void print_csv(const int* arr, size_t element_count)
{
if (element_count != 0){
printf("%d", arr[0]);
for (size_t i = 1; i != element_count; ++i)
printf(",%d", arr[i]);
}
putchar('\n');
}
int main()
{
int arr[] = {1, 2, 3};
print_csv(arr, sizeof(arr) / sizeof(*arr));
}
() · 2020-08-23 22:39
>>17019
>>16953
These smell so bad I had to open window. Lainons please don't make me puke by posting such stuff.
t. kernel and system programmer
bit · 2020-08-24 19:17
>>20418
Pardon, but just because you think it is faster/shorter, it does not have to be. C/C++ compilers are designed to perform a soykaf of optimizations.
Thus, I just rewrote your code to use a for loop instead of the goto. A logical difference is that your original code would try to access the array at least once, even if it is empty. This potential bug is not present in the more human readable altered version.
c
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3};
size_t i = 0, element_count = sizeof(arr) / sizeof(*arr);
for (; ++i < element_count;) {
printf("%d", arr[i]);
putchar(',');
}
putchar('\n');
return 0;
}
The compiled output can be compared using godbolt's compiler explorer. I just tried your original code against the modification, using a current gcc with the -O2 flag. The result is that this altered code without gotos has less opcodes; https://godbolt.org/z/xjhr3x
Takeaway lesson: never try to smart out the compiler, because this just introduces bugs and in most cases never brings a performance improvement.
Zero Cool · 2020-08-24 19:27
>>20441
Small extra: even with -O0 both programs are resulting in the same amount of operations.
Another extra: if you also alter the for loop to look sane, the amount of opcodes with -O0 is even shorter for the version below.
c
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3};
size_t i, element_count;
for (i = 0; i < sizeof(arr) / sizeof(*arr); i++) {
printf("%d", arr[i]);
putchar(',');
}
putchar('\n');
return 0;
}
Inb4, I am aware that less opcodes does not always mean faster code. It was just my stupid benchmark.
sizeof · 2020-08-24 19:30
>>20441
>>20442
Pardon, last update - sorry, I should have thought before posting, I know.
I think the biggest blocker is the printf function call, which is a complete overkill for just printing a single int. For example, use atoi.
Lady 3Jane.. · 2020-10-09 15:59
>>17247
human readable enterprise code is not aesthetic, so you are in the wrong thread.
Colmerauer · 2020-10-09 16:40
Zen code:
main(){}
cdr · 2021-04-05 15:33
>>434
>and from some tests I did a while ago it seems to be slower than using a temp variable.
I would imagine that wouldn't be the case. Aren't bitwise operations generally faster than messing around with values but since this post is 4 years old and I haven't actually tested it, I should actually check this.
nthcdr · 2021-04-18 07:48
lisp
(defmacro alambda (parms &body body)
`(labels ((self ,parms ,@body))
#'self))
(defun fib (n)
(assert (>= n 0) nil "'~a' is a negative number" n)
(funcall
(alambda (n)
(if (>= 1 n)
n
(+ (self (- n 1)) (self (- n 2)))))
n))
Spooky · 2021-05-23 13:00
>>8032
I might be wrong, but wouldn't this not work depending on the system's endianness?
sage · 2021-10-03 21:54
>Ctr+F Duff's device
>Phrase not found
Technician · 2021-10-06 02:15
>>25947
Depending on the CPU architecture, actually.