Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I agree with you, though in the q world people tend to take it to the extreme, like packing a whole function into a single line rather than a single screen. Here's a ticker plant standard script from KX themselves; I personally find this density makes it harder to read, and when reading it I put it into my text editor and split semicolon-separated statements onto different lines: https://github.com/KxSystems/kdb-tick/blob/master/tick.q E.g. one challenge I've had was generating a magic square on a single line; for odd-size only, I wrote: ms:{{[(m;r;c);i]((.[m;(r;c);:;i],:),$[m[s:(r-1)mod n;d:(c+1) mod n:#:[m]];((r+1)mod n;c);(s;d)])}/[((x;x)#0;0;x div 2);1+!:[x*x]]0}; / but I don't think that's helping anyone


There's a difference between one line and short/terse/elegant.

  {m:(x,x)#til x*x; r:til[x]-x div 2; 2(flip r rotate')/m} 
generates magic squares of odd size, and the method is much clearer. This isn't even golfed as the variables have been left.


Do you know which method is this? Euler's by any chance? And do you have an idea how one would prove that it creates a magic square? It's actually one of my inspirations for writing this, the relationship between the code that does something and the proof that the code actually does what it claims. I'd argue an LLM would find the proof helpful if it were asked to generalize an existing function in some way


Oh nice solution, thanks for sharing!


When Q folks try to write C: https://github.com/kparc/ksimple


Representative example:

  //!malloc
  f(a,y(x+2,WS+=x;c*s=malloc(y);*s++=0;*s++=x;s))     //!< (a)llocate x bytes of memory for a vector of length x plus two extra bytes for preamble, set refcount to 0
                                                      //!< and vector length to x in the preamble, and return pointer to the 0'th element of a new vector \see a.h type system
  f(_a,WS-=nx;free(sx-2);0)                           //!< release memory allocated for vector x.
  G(m,(u)memcpy((c*)x,(c*)y,f))                       //!< (m)ove: x and y are pointers to source and destination, f is number of bytes to be copied from x to y.
                                                      //!< \note memcpy(3) assumes that x/y don't overlap in ram, which in k/simple they can't, but \see memmove(3)
  //!memory management
  f(r_,ax?x:(++rx,x))                                 //!< increment refcount: if x is an atom, return x. if x is a vector, increment its refcount and return x.
  f(_r,ax?x                                           //!< decrement refcount: if x is an atom, return x.
         :rx?(--rx,x)                                 //!<   if x is a vector and its refcount is greater than 0, decrement it and return x.
            :_a(x))                                   //!<   if refcount is 0, release memory occupied by x and return 0.
Reminds me a bit of both the IOCCC and 70s Unix C from before anyone knew how to write C in a comprehensible way. But the above is ostensibly production code and the file was last updated six months ago.

Is there some kind of brain surgery you have to undergo when you accept the q license that damages the part of the brain that perceives beauty?


Lol no. It's just Arthur Whitney style C (with the repo in question being originally written by Whitney).

Whitney kind of set the stage for this but it got adopted informally as a style by the people at IPSA (I. P. Sharp Associates) and spread throughout the industry.

Whitney style C isn't great for everything but it's not bad for interpreter writing and other text/stream touching tasks.


author of the annotated version here.

> representative example

this is grossly taken out of context (which is explicitly stated at the very top of the corresponding readme, https://github.com/kparc/ksimple).

ioccc is often brought up in such HN rants, but the comparison is off mark completely. if you can't read this, you're better off writing some python or some such. this works exactly because it is not obfuscated. this code can't be more regular. tripwires (lack of malloc errno check, possible overflow of refcount) are given as exercises.

> Is there some kind of brain surgery you have to undergo when you accept the q license that damages the part of the brain that perceives beauty?

this code has absolutely zero to do with commercial system k4/kdb+, where did you get that idea? this is published under MIT license. would you like to be reminded of the terms, or fancy an explanation of what they mean? all of them implicitly state that if you're unhappy with the terms you're very welcome to walk away.

hopefully, no brain surgery required for you, god forbid. just an open mind, in methaphorical sense, healthy sense of humour and common sense that the less you type the more you think.

you are also welcome to share examples of code which tickle your sense of beauty, authored by you or someone else.

now, stand straight and defend your argument. we're all ears.


When EAX and RAX take too long to type.


oh no, not really.

this is not writing in assembly, and definitely not in bytecode.

but if you are indeed an elite intel(R) assembly coder, and old enough for eax and rax to have taken too much toll on you, or your time away from your family, and of your career as a computer programmer in general - you should probably consider a more modern, more simple and elegant isa, which is now omnipresent, royalty-free, has a huge encoding margin for custom extenstions, and spares you from the childhood trauma of 16 GPRs. it is called riscv.

k family languages isn't asm. it doesn't expect you to hardly ever need anything other than x,y,z in terms of function arguments. this is why they are so conveniently implicitly auto-declared for you in your function - just reference them, done.

it is useful, man. it works.


I've been dabbling in programming language design as of late, when trying to decide if including feature 'X' makes sense or not, with readability being the main focus I realized some old wisdom:

1 line should do 1 thing - that's something C has established, and I realized that putting conceptually different things on the same line destroys readability very quickly.

For example if you write some code to check if the character is in a rectangular area, and then turn on a light when yes, you can put the bounds check expressions on the same line, and most people will be able to read the code quickly - but if you also put the resulting action there, your code readability will suffer massively - just try it with some code.

That's why ternary expressions like a = condition? expr1: expr2 kinda controversial - they're not always bad, as they can encode logic about a single thing - if said character is friendly, turn the light color should be green, otherwise red - is a good example - but doing error handling there is not.

I haven't been able to find any research that backs this up (didn't try very hard tho), but I strongly believe this to be true.

A nice thing is that some other principles, like CQRS, can be derived from this, for example CQRS dictates that a function like checkCharacterInAreaThenSetLightState() is bad, and should be split up into checkCharacterInArea() and setLightState()


I'd perhaps generalize that to "it's useful to have visual grouping correlate with semantic grouping"; applies to separating words with spaces, sentences with punctuation, paragraphs with newlines, lines of code, UIs, and much more.

An important question for this also is what qualifies for "single thing"; you can look at a "for (int i = 0; i < n; i++) sum += arr[i]" as like 5 or more things (separate parts), 2 things (loop, body), or just one thing ("sum"). What array languages enable is squeezing quite a bit into the space of "single thing" (though I personally don't go as far as the popular k examples of ultra-terseness).


I'd say I'd decompose this into 2 'units'

- iterate through the array arr,

- sum its elements

of course, since C is a low level language, implementation details seep in there but those are the 2 major logical concepts that mentally can be quickly parsed as a single unit each.

Some languages allow reductions on collections, so the actual iteration becomes logically part of that single unit, so it might count as one, but I'd say that's the absolute upper bound of complexity you should stuff into a singlwe line.

The goal here is to make every statement conform to a template so that your brain quickly recognizes it and you can move on, rather than you having to break it apart bit by bit to figure out the goal.


Hey, another language with smileys! Like haskell, which has (x :) (partial application of a binary operator)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: