Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Why is C++...

Name: Anonymous 2011-12-07 12:06

...so bad? Why does it have such a bad reputation?

I'm an experienced C++ programmer and, while the language has warts, I can't understand the reason for the enormous amount of criticism against the language.

I'd like to hear the honest opinions of /prog/rammers in this regard.

Name: Anonymous 2011-12-17 15:14

>>240
What about nested lambdas? And what is `#`? Clojure is abomination!

Name: Anonymous 2011-12-17 15:16

>>240
stack based langauge.
enjoy your swap [uncons uncons pop] dip uncons uncons pop dip uncons swapd cons cons cons cons dupd swap ;

Name: Anonymous 2011-12-17 15:31

>>241

that's a good point. It is kind of typical in functional languages to have constructs that allow for quick writing of correct code, but if you were to go and try to extend the code a bit, it becomes impossible, and the entire routine ends up having to be replaced with something that is equivalent to a c/c++ for loop.

>>242

swap dup mul ery day

Name: Anonymous 2011-12-17 15:43

>>237
The (remove-duplicates (cdr xs)) call is a tail call, the (cons (car xs) (remove-duplicates (cdr xs))) is not. The first reuses the caller's stack frame, the second does not. (remove-duplicates '(a b b c c c d d d d)) will use only 4 stack frames in languages with proper tail calls, Clojure will use (length '(a b b c c c d d d d)).
That's what I meant with ``tail recursion isn't always tail recursive'': the recursive call doesn't have to be in tail position in all cases to benefit of proper tail calls.

>>238
Seriously, the lack of laziness in a lisp is a bigger deal breaker form e than the lack of automatic tail call elimination. Not to mention immutable sets/vectors/associative arrays.
And that's also wrong, or at least, it's wrong in Racket and some Scheme implementations, and probably in CL too.
SRFI-45 (lazy/eager/delay/force) isn't rocket science either, it's implementable in half an afternoon of macros, but you can't understand that without, you know, using a real Lisp.

Name: >>244 2011-12-17 15:43

And, laziness (which is not a silver bullet) and proper tail calls aren't mutually exclusive.

Name: Anonymous 2011-12-17 15:55

>>238
Someone hasn't read his SICP today

Chapter 4.2.3, truly lazy lists.

Name: Anonymous 2011-12-18 2:53

>>236
All I see is


(cudder (cudder (cudder (cudder (cudder 'autism)))))


That being said, please take your extraordinarily pointless waste of parentheses, and remove yourself from this thread, 'chap'.

Name: Anonymous 2011-12-18 2:57

>>244
But what you describe as tail call is in tail position wrt cond as described by your favorite RnRS.

Name: Anonymous 2011-12-18 3:19

>>241
You can't nest #()'s in Clojure, (Though I don't see why not)

But it's just a reader macro over fn, which is the same as lambda in other lisps, but is 3 fewer keystrokes.

But for little lambdas (like ones going in map/filter/reduce) I use it all the time. It's just fewer parens.

>>239
I'd say Clojure is useless for anything but processing data structures and dealing with state intelligently.

(not a joke. Sometimes you want to deal with state unintelligently, say, for performance reasons. Clojure is not your man, in these cases. It's also no Erlang -- no model for distributed computing (yet.))

But after working on some things in Clojure, I can't look at the way I dealt with data structures before (by mutating them) the same way. I see it as an optimization. (Clojrue calls them 'transient's.) Clojure lets you see the functional light without having to deal with category theory and  type systems. It's laid back functional programming, which is just groovy. But moreso than Groovy.

Name: Anonymous 2011-12-18 3:20

>>247

here ya go:


struct refc {
  int count;
  void (*destructor)(void*);
};

#define INC_REF(p) if(p) ((struct refc*)(p))->count++
#define DEC_REF(p) if((p) && (--(((struct refc*)(p))->count)) == 0); ((struct ref*)(p))->destructor(p)

struct list {
  struct refc refc;
  void* car;
  struct list* cdr;
};

void destroy_list(struct list* lis);

void* cons(void* car, struct list* cdr) {
  struct list* a = malloc(sizeof(struct list));
  assert(a);
  a->refc.count = 0;
  a->refc.destructor = (void(*)(void*))destroy_cons;
  a->car = car;
  INC_REF(car);
  a->cdr = cdr;
  INC_REF(cdr);
  return (void*)a;
}

void destroy_list(struct list* lis) {
  DEC_REF(lis->car);
  DEC_REF(lis->cdr);
}

void* remove_duplicates(void* xs, int(*eq)(void*,void*)) { // removes the consecutive duplicates in a list
  if (xs == NULL || xs->cdr == NULL) return xs;
  if(eq(xs->car, xs->cdr->car)) return remove_duplicates(xs->cdr); // tail recursion
  return cons(cs->car, remove-duplicates(xs->cdr)); // no tail recursion
}

Name: Anonymous 2011-12-18 3:26

>>250

I forgot to pass in eq into the recursive calls. shame on me.

Name: Anonymous 2011-12-18 3:36

>>250
#define INC_REF(p) ((p) && ((struct refc*)(p))->count++)
#define DEC_REF(p) ((p) && (--(((struct refc*)(p))->count)) == 0 && ((struct ref*)(p))->destructor(p))

This way they're expressions instead of statements.

Name: Anonymous 2011-12-18 3:47

>>252

that's cool and all, but the expressions don't really have sensible values to evaluate to. INC_REF(p) is true whenever p is not null. DEC_REF(p) is true whenever p is not null, and p's reference count went down to zero, and p was successfully destroyed by its destructor. I guess it could come in handy to know these values, so it doesn't hurt to have them.

Although I suppose the main advantage is that if the programmer types:


int t = c*INC_REF(p);


then the compiler wont say something completely strange after expanding it to:


int t = c*if(p) ((struct refc*)(p))->count++;


why u try to multiply c by an if statement?

Name: Anonymous 2011-12-18 3:59

>>250

and destroy_list should have called free at the end.

Name: Anonymous 2011-12-18 5:38

>>248
Tail positions are transitive, and cond itself is in tail position wrt the whole procedure.

>>249
But it's just a reader macro over fn,
Clojure has no reader macros (yet), just special syntax.
Also, fn is a bad name for such a fundamental special form, they could've called it x, f or obj as well. I would bitch less if it was called fun.
which is the same as lambda in other lisps, but is 3 fewer keystrokes. But for little lambdas (like ones going in map/filter/reduce) I use it all the time. It's just fewer parens.
I use λ or cut anyway for small procedures.

As for the rest of your post, although Clojure is not the first Lisp with purely functional data structures, I do envy its first-class STM support, and things like transients.

Name: Anonymous 2011-12-18 6:10

>>244
This idea that Clojure is not real Lisp because of the (seeming) extra syntax is just a kneejerk reaction. Clojure is a language defined in terms of its own data structures -- it just has 4 of them instead of 1. The thing that makes lists convenient for homoiconicity is their immutability. Invent immutable sets, vectors, and maps, and suddenly they're fine to have at the meta level as well. It does NOT make writing macros harder. #{1 2 3} is not syntactic sugar for (set 1 2 3). It's just a set. Both at compile time and run time. It does NOT become irrelevant after a few levels of macro, because they're always there, just like lists, symbols, and numbers. I think a lot of Lispers and Schemers don't realize this, or don't internalize it properly.

I gave up on Racket/Scheme when I tried playing around with hash tables and found that there were like 12 of them, all mutable. fuck that. There are some basic things I want served to me on a silver platter when I grab a high level language. Associative arrays with a literal form is one. call/cc? Less so.

I like that Clojure doesn't treat general purpose good ideas as domain specific ideas.

like Scheme does

Name: Anonymous 2011-12-18 7:11

>>256

I agree. When I see scheme code that other people have written, all I see is imperative stuff that relies on set! and pseudo object systems. It's like it tries to be this different, simple language, but people end up using it to mimic all the normal stuff they are used to in mainstream imperative languages, but the lack of direct support for these techniques make it more inefficient, and more awkward for reading.

Name: Anonymous 2011-12-18 9:10

Standard scheme only encourages by convention functional style writing but it never forces it like the pure languages. From my experience scheme code usually gets slightly shorter if you do avoid set!, usually by rewriting in tail call style.

>>256
I find call/cc quite useful actually, and 6 of those 12 hash table types are immutable, what's the issue with them? Btw there is 12 to accommodate the 3 equalities (hasheq is faster than hash when your data can be compared with the simple eq? instead of the all-powerful equal?) and weak/nonweak.

For what its worth on immutability, Racket actually dropped the R5RS standard set-car! and set-cdr!, mutating variables across modules isnt possible and DrRacket highlights mutating variables in red.

Name: Anonymous 2011-12-18 13:49

>>257
Because that's a common solution to some problems, so why wouldn't you use it? Scheme isn't magic, it's just a better programming language. If at the end of the day, state is the best way to model a problem, you use state. The only people that would cry would be the Haskell Nomad.

Name: Anonymous 2011-12-18 17:52

>>256
First, both CL and Scheme have more than one data structure, Scheme has strings, vectors, and conses, and most implementations have more, like Racket and hashes.

#(1 2 3) is not syntactic sugar for (vector 1 2 3). It's just a vector. Both at compile time and run time. It does NOT become irrelevant after a few levels of macros, because they're always there and they would be there even if they were some kind of crippled data structure.
#hash[eq[v]]((x . 1) (y . 2)) is an hash (in Racket). See why there are 12 of them in >>258. Immutable hashes are backed by Red-black trees (IIRC), to achieve sharing. I agree the syntax for them is a little (too much) heavyweight. It also has box literals, regexp/perl-compatible-regexp literals, and bytestring literals. What Racket is really missing is set literals, I wish it had them on {}.

CL has #An() literals for arrays. They really are arrays and blah blah blah. I can't talk much for CL since I don't use it.

Conses are mutable both in CL and Scheme, so that's not why they are used for homoiconicity, but because conses can make trees, and Lisp source code is, well, an abstract syntax tree.
Being defined in terms of a data structure doesn't mean forcing it on lambda-lists (i.e. on fn and let).
Do you want vector lambda-lists? It's ok:
(define-syntax-rule (fn #(x ...) bd ...)
  (lambda (x ...) bd ...))

((fn #(x y) (+ x y)) 2 3) ; => 5
(vector? #()) ; => #t

Why aren't vectors used in macros? Because there's no point to use them instead of lists.

So, you want hash literals so much to renounce to call/cc? That's too bad, because I have both. Now stop posting these uninformed idiocies on Scheme and Lisp in general.

Clojure has a better support for sequence abstraction than most Schemes (that I know), though. CL and Racket are ok in this regard, but Racket's feels kind of unnatural. Maybe it's just me.

>>257
set! and pseudo object systems are not idiomatic Scheme, except when writing those pseudo object systems (like SICP's).

Name: Anonymous 2011-12-19 0:08

>>260
>Why aren't vectors used in macros? Because there's no point to use them instead of lists.

actually I think in cases where the car is not interpreted significantly differently from the cdr, using a vector instead of a list makes a lot of conceptual sense and gives better visual cues as well. That's basically Clojure's idea...

Name: Anonymous 2011-12-19 3:53

>>261
using a vector instead of a list makes a lot of conceptual sense
For lambda-/argument lists, vectors? Scheme's basic lambda-lists make much more sense than using vectors with some special & keyword to mark rest arguments, because it kind-of pattern matches with the argument list.
((lambda (x y) ...) 1 2) => '(x y) '(1 2) => ((x 1) (y 2))
((lambda (x . y) ...) 1 2) => '(x . y) '(1 2) => ((x 1) (y (2))
((lambda x ...) 1 2) => 'x '(1 2) => ((x (1 2)))


and gives better visual cues as well.
Where's the difference between ))))))))) and )))])])))]))), except the second is harder to type?
Also, R6RS has [] aliased to (). I wish they were vectors, though.

Name: Anonymous 2011-12-19 5:25

>>262
harder to type
only if you use notepad

Name: Anonymous 2011-12-19 8:06

>>263
If you've got the editor to hold your hands, I see no point in having []s in first place.

Name: Anonymous 2011-12-19 11:49

>>264
derp

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List