HN user

okmjuhb

189 karma
Posts0
Comments37
View on HN
No posts found.

Let's say you wanted to implement I/O in a language without side effects. You could put all your interactions with the world in a special "World" object. Every time you called world.putString("foo"), you'd get back a new world object that represents the state of the world with "foo" having been written out.

So the code (quoting from samstoke's hello world):

    main :: IO ()
    main = do
      putStrLn "Please enter your name"
      name <- getLine
      putStrLn ("Hello " ++ name ++ "!")
would get translated to:
    main :: World -> World
    main world = let newWorld = putStrLn world "Please enter your name" in
                   let (newerWorld, name) = getLine newWorld in
                     let newestWorld = putStrLn newerWorld ("Hello " ++ name ++ "!") in
                       newestWorld
Note that this makes the order of operations explicit, and that no World needs to be modified. Note also that now main has to take and return one of these World objects, so that a World needs to be threaded through all computations that will interact with the World (just like IO actions can only be executed from within other IO actions).

A monad lets you thread implicit state through a computation.

"Assuming the US Mint and my bank weren’t trying to scam me, that only left myself as the scam artist and I knew I wasn’t trying to cheat anyone, so that took care of that concern."

I guess if ignorance of the way he's hurting people counts as "not cheating them" this is true.

He gets the airline miles because the US mint takes in between a 1% and 3% loss on the transaction to pay the credit card company. They also lose money when they ship him the coins for free. The reason the US mint is willing to do this is because coins are so much cheaper for them in the long run than bills, once they go into circulation; they're paying this guy and UPS a fee for helping them put dollar coins into circulation. This guy is taking that fee, but not putting the coins into circulation. Its not like the money in his rewards account appeared out of nowhere.

The argument "well, passing by reference gets compiled to passing a pointer by value so really there is no passing by reference" is silly because passing by reference is a description of language semantics and function call evaluation. Your argument applies just as well to the statements "there is no such thing as lambda functions" or "there is no such thing as garbage collection" because those language features also get converted into representations that don't have either of them present.

The Java code you give isn't an example of passing by reference because, while you can change the value that x points to in Java, you can't change x to point to something different. No java function can change its arguments; the example you gave has the java function changing something that its argument points to.

Your argument that Java people can call language features the same name as distinct language features is: a. dumb, because it's just "words mean whatever anyone wants them to mean", and b. doesn't come anywhere close to applying here; the quotation at the end of my last response: "there is exactly one parameter passing mode in Java - pass by value" is a direct quote from 'The Java Programming Language'. The authors of Java disagree with you.

More from them: "All parameters to methods are passed 'by value'. In other words, values of parameter variables in a method are copies of the values the invoker specified as arguments. If you pass a double to a method, its parameter is a copy of whatever value was being passed as an argument, and the method can change its parameter's value without affecting values in the code that invoked the method.

...

You should note that when the parameter is an object reference, it is the object reference - not the object itself - that is passed "by value." Thus, you can change which object a parameter refers to inside the method without affecting the reference that was passed. But if you change any fields of the object or invoke methods that change the object's state, the object is changed for every part of the program that holds a reference to it.

...

Some people will say incorrectly that objects are passed "by reference." In programming language design, the term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory.

...

The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode - pass-by-value - and that helps keep things simple."

Your last few paragraphs are beside the point; the question is not about which languages offer which levels of abstraction; the point is that different abstractions have different names and Java doesn't offer the abstraction named "pass by reference".

"No the real problem is that you fail to understand that Java gets to call these things what ever it likes because language has context."

This is silly; "pointer" and "reference" both had meanings before Java came along. If Java called pointers "names" instead of "references" it wouldn't mean that its function call semantics were pass-by-name either. And besides; if your argument is that we should use the Java terminology to describe all the aspects of Java under discussion, the fact that the all the Java designers make explicit that the function call semantics pass references as values, not objects as values.

"And your example fails to compare apples to apples. In Java Integer is an object, but int is not. You are confusing Java things with C++ things."

The argument applies if you use int in place of Integer just the same; or if you make a C++ Integer wrapper class analogous to the Java one. Any comparison here will of course be apples to oranges because C++ supports pass by reference and Java does not. The swap function is impossible to write in Java because it requires allowing called functions to change the values viewed in the caller, which is almost the definition of passing arguments by value.

"As you can see, Java is not C++, and so your C++ terms and definitions do not apply here. Thank you for playing. Move along."

Leaving aside the childish and insulting tone, the definition of "pass by reference" has nothing to do with C++; if the code were in perl it would still be pass by reference, because "pass by reference" has a meaning that exists outside of any particular programming language and describes a concept. Java function calls are not part of that concept; "there is exactly one parameter passing mode in Java - pass by value".

This is not at all correct because passing by reference and value have defined and distinct meanings. Consider the difference between C++, which has actual pass by reference: void swap(int& x, int& y) { int t = x; x = y; y = t; }, and Java: void swap(Integer x, Integer y) { Integer t = x, x = y; y = t; }. The C++ version will result in changes to the variables in the calling function and the Java version will not.

The real problem is that Java created needless confusion by calling its pointers references for purely marketing reasons.

The history behind this actually goes the other way if I remember correctly; it was unclear for a time whether or not this sort of thing was allowed. The standard was modified so that Duff's device would be legal code after it was being used.

Why Python? 16 years ago

I'm surprised no one has mentioned yet what I regard as the key reason decorators are useful: they maintain the property that you can always find the definition of a function named "foo" by textually searching for "def foo". Lots of alternate syntaxes break that.

Baby Rudin is a great choice, especially for self study, since there are a number of study guides for it that go through solutions, additional explanation of material, etc. I'd recommend against the chapters on differential forms, though, just because the treatment is outdated. Marsden and Hoffman's approach is to focus on explanations for why theorems are true before giving proofs, which some people find useful.

Axler is a good choice for linear algebra. Dummit and Foote is the standard choice for algebra generally. I'm of the opinion that we should teach algebra before linear algebra in general, but this seems like a minority view.

The much more self-serving reason to spend time learning about activities outside of your specialty: applying techniques of your discipline to another discipline is a great way to crank out some easy papers for the second discipline's journals. There's some good work waiting to be done applying dynamic code generation to graphics, artificial intelligence, or probably some other fields. This sort of work probably wouldn't cut it in a systems journal, but would probably excite some people in the respective target groups.

The interesting thing about compiler writing is the drastic reduction in complexity that's happened. There are essentially off-the-shelf tools that can be used to handle everything before semantic analysis and everything after conversion to a reasonably high-level IR. This has dramatically reduced the cost of language experimentation; it's now feasible to bang out a new language in a day or two (assuming you're familiar with yacc, LLVM, etc.), and generate efficient code on a number of target architectures.

These tools mean that "learning to write a compiler" can take several different paths; on the one hand, we could learn about how each of these tools work (e.g. "how to write a parser generator", "machine-independent optimizations", "code generation", etc.). This is the approach taken by the dragon book. This gives the background theory and mathematics behind compiler-writing (and will likely be something people need to know if they want to write for instance an LLVM optimization pass). The problem with this is that, because of the trends mentioned above, it has little to do with the day-to-day of actual compiler writing and language experimentation (this is only somewhat true, since most "real" compilers will have a custom-written frontend and at least a little bit of knowledge about the target architecture).

The other approach is to use pre-written tools, to focus on language design decisions and applications. To be honest I'm not familiar with any resources that do this particularly well. This is the approach taken by most of the "we're going to build a compiler!" websites mentioned on the Stack Overflow post. This approach is probably more useful for most of the people who want to "write a compiler", but it leaves people with a very shallow knowledge of what's happening beneath the surface of the APIs they use.

I don't mean to imply that one of these approaches is "better" than the other (and indeed, the second requires a little bit of the first - it's difficult to debug an automatically generated parser without knowing at least a little bit of the theory), but it's important to know which approach you're aiming for, and trying to optimize based on that goal. Going to the Dragon book as a "how-to" is a disaster waiting to happen.

Not really "brand new" at all. It wouldn't be out of place in the first week of an Algebra course.

You don't really need much math background to understand the proof. At the top, where he writes pi = (top line of numbers, bottom line of numbers), he means the permutation that sends the first element to the second place, the second element to the third place, and so on.

If you think about it, every permutation can be split into cycles of this form (a -> b, b-> c, c->d, ..., e->a). One of these cycles, that's of length K, is called a "K-Cycle".

I think that's the only terminology you need to follow the proof.

[dead] 16 years ago

On a related note, most people today associated ancient Roman art with their statues. In fact painting and portraiture was a widely practiced art; it's just that statues stand the test of time better.

There's some roman paintings here: http://www.art-and-archaeology.com/roman/painting.html if anyone's interested.

I almost couldn't make it through without going crazy:

>Imagine you ran a restaurant. A very prestigious, exclusive restaurant. To attract top talent, you guarantee all cooks and waiters job security for life. Not only that, because you value honesty and candor, you allow them to say anything they want about you and your cuisine, publicly and without fear of retribution. The only catch is that all cooks or waiters would have to start out as dishwashers or busboys, for at least 10 years, when none of these protections would apply. It sounds absurd in the context of the food-service industry—for both you and your staff.

Except that the reason this is crazy is that dishwashing and bussing tables have little to do with cooking, and that the goal of a restaurant is to make money. A much better example would be one in which the goal of a restaurant is to produce new and exciting foods, and where all head chefs have to start out as a station chef and prove themselves there, first. This system would actually make a lot of sense then.

The article then goes on to blame tenured faculty salaries for increasing costs of tuition; never mind that academic faculty salaries have either just kept up with inflation or fallen behind it for the past 30 years, that in fact administrative salaries have ballooned during that same period, and that the fraction of tenured faculty has dropped substantially. Some of the numbers they give are at first glance highly suspect (35 years of professorship costing $12 million means, not adjusting for inflation or the opportunity cost of money, that a professor costs a little more than 340 thousand dollars a year over her lifespan - a number that seems hard to justify).

The argument about affecting teaching and interdisciplinary study is a red herring - if we put too much weight on (e.g.) publishing as opposed to teaching in deciding whom to give tenure, there's no reason we won't do so when we're hiring for our renewable 7-year contracts or whatever alternative system is implemented. The problem is academic priorities, not tenure. (Though I'm not taking a stand on whether or not teaching is valued too much or too little as it is, and likewise with interdisciplinary studies).

The arguments that tenure hurts intellectual freedom for those without it is ok, but it also misses the point of tenure. Tenure makes it difficult for political decisions to dictate research directions. Tenured medical ethicists can write honestly about abortion without worrying that in 10 years the social tides may have shifted and they suddenly have to defend their jobs because of something a TV news pundit dug up on them. The article is somewhat correct in that young researchers might be afraid of saying inflammatory things because it could hurt their chances of getting tenure later, but there's no reason any alternative system is necessarily better in this regard.

>Critics say that tenure hurts students by making professors lazy. Course loads vary widely from school to school: At some public universities, professors teach nine or 10 courses. At smaller schools, they teach as few as one or two, totaling as few as 140 classroom hours a year. If you can't be fired, what's to stop you from refusing to teach an extra course? "I honestly don't know what a lot of academics do a lot of the time," says Taylor.

This is particularly infuriating. The article makes it seem as though Taylor is an academic faculty member, so it baffles me that he doesn't know any better. Teaching even one course is a pretty substantial amount of work. Doing it while trying to get grants and do research requires a tremendous amount of effort. The professor's I've known are, to a person, among the most dedicated and hardworking people I've ever met.

>But the clincher for the anti-tenure argument may come from the very people it is supposed to benefit: academics. Specifically, young academics. Consider the career path of an aspiring full-time tenured professor: Four years of college, six years getting a doctorate, four to six years as a post-doc, and then six years on the tenure track. By the time you come up for tenure, you're 40. For men, the timeline is inconvenient. But for women who want to have children, it's just about unworkable.

This is perhaps my favorite paragraph in the article, and it by itself might be enough to justify some of the proposed fixes. The alternatives to the current system, the "modifications to tenure", are all interesting ideas that I'd like to see explored more fully. I wish that there were more to them than a few throwaway sentences in the second-to-last paragraph of the article.

The solution would be then to do autoconversions as appropriate or return an error.

The compiler already deals with this issue with the ?: operator. It's a readability and maintenance problem there, too. It'd be easy to do; the language designers chose not to.

To be more specific: the return type of the lambda can be omitted for a lambda whose body is just "return {expression}". The compiler could, if it wanted, always deduce the return type (since implementing type inference would be easy). The fact that it doesn't isn't to make it easy for compilers; it was a design decision of the language: having unspecified return types for complicated pieces of code hurts readability and maintainability.

I always do my first draft of any nontrivial large system by writing the code out longhand, after having heard it recommended by multiple people I respect. My perception is that the resulting code is cleaner and better documented, and that my error rate has dropped to almost 0.

Writing your code this way encourages a "write as you would speak" tone in the resulting code, better decomposition, and better documentation. It also means that each line gets reviewed from a fresh start at least twice before making it to the computer.

The biggest problem comes when you're working with a large API you don't know well; you're frequently forced to experiment with it in a manner that this sort of batching doesn't really handle well.

Assume we encode the data on acid free paper with color-retaining ink using colored squares of size 1/64" x 1/64", using one of 64 colors in each square. There are then 4,096 of the squares in 1 square inch, so (assuming we print on 8"x10" regions) we can fit 327680 squares on a side of a sheet of paper, so that there are 655360 squares on a sheet of paper (if we use both sides). Each square encodes 6 bits of information, so we have 3932160 bits per piece of paper, or 491520 bytes, which is 480 KB.

At this rate, encoding a gigabyte requires 2,185 pages. As an aside, this is only 5 pages fewer than are contained in the "Art of Computer Programming" box set.

We can comfortably fit a gigabyte, then, on printed paper, in a 10"x12"x5" box. A terabyte will then fit comfortably in a 10'x10'x5' space. Throw a few of these together to get 5 terabytes. Let's add, say, 1 TB more of error correcting codes. In the unused margins of each page add in some information about alignment, a printing of all the colors used (to try to protect against inks changing color over time) and the page number. All together, this is certainly big, but could probably fit in, say, a tractor-trailer. Throw in some books describing the data format and the meaning of the data, and you're done.

It's worth mentioning that they're writing for DSP systems. More mainstream CPUs have a larger instruction cache (and smarter eviction policies), but the size of the hot code paths are (I imagine; I'm not terribly familiar with DSP) likely not much bigger, so that the problems they mention need solving less frequently for typical applications.

A few loosely related thoughts as to why I'm fond of the University system (in response to the negative tone of some of the comments here and at techcrunch):

- It's the only socially acceptable way to spend years simply learning as a full time job.

- The argument that "lectures will soon be online" only makes sense if you believe that physically being present in lectures is the way that people gain knowledge in school.

- University admissions maintain a level of intelligence in incoming classes that I don't think an online community ever could - so that the students who interact at a university are interacting in a productive way.

- Physical colocation is just a better way of interacting with people than communicating online is.

Measuring stock performance by looking at one of the biggest bubbles in recent years and comparing it to one of the biggest crashes in recent years is a little bit dishonest. Given that this article is writing to young people interested explaining how they should invest if they're interested in their financial situation 30 years from now, a 30-year outlook is more reasonable.

In general I don't like the idea of credit checks before employment, but there's a few obvious cases where it's useful.

If I'm hiring an employee who will be handling cash, or who will control purchasing decisions, or who will have access to information my competitors want, it's important to me to know that my employee won't ever be in desperate enough financial circumstances that they feel compelled to steal or accept a bribe.

I wonder how many Hacker Newsers really remember what it was like back before the GPL and the FSF. The availability of a high-quality open source unix system is pretty much the defining quality of modern computing, and it took us out of the dark ages of a half dozen mutually incompatible proprietary OSs, compilers, and commandline utility packages (sometimes broken - with fixes impossible).

Stallman's contribution is much greater than that of cheerleader or discussion framer - the ecosystem that exists in large part because of him is, I suspect, tremendously important in the day to day lives of many of the people reading this.

Will it optimize? 16 years ago

const only means that the function is not allowed to change memory through that reference. It says nothing about aliases to the same memory.

But the "what if another thread changes the string" issue is a red herring. The question to keep in mind when optimizing in a multi-threaded context is "does the output of the compiler generated code correspond to at least one possible interleaving of threads". Since this thread doesn't do any synchronization, it's possible that all the function executes without being interrupted by another thread, so this is a sound optimization.