1. 37
  1.  

  2. 14

    I use the word “signature” a lot, but I rarely see anyone else use it, and sometimes I wonder if anyone understands what I mean.

    Unless we are talking about different things, I use the term “function signature” a lot. But then again, I am quite influenced by languages like OCaml and Haskell where it’s pretty normal to talk about signatures all the time.

    1. 3

      lol I just thought it was generally accepted that “signature” was the proper term to describe that. XD Hope I didn’t confuse too many people

      1. 2

        You mean “method signature” in Java, right? ?

        1. 1

          I use “signature” all the time too, but then I work primarily in F# around other F# programmers.

        2. 14

          Java is statically typed: Java code is 70% type names by volume.

          Lots of funny, well deserved jabs at various languages in this article. This quote is my favorite.

          1. 6

            The amount of discussion that this article will engender is a sure sign: nomenclature actually is a problem.

            I think it’s a symptom of the culture surrounding programming and computer use, where almost everyone teaches themselves and thus idiosyncratic exposure and idiosyncratic understandings are the rule, rather than the exception.

            1. 15

              I think the volume of discussion is more indicative of the ease with which people can form opinions about the subject than a sign that there’s a serious problem.

              I have not observed much difficulty explaining python or java or C semantics to people interested in learning. The difficulty really only arises when a third party overhears (reads forum comments) and decides to interject their comic book guy technically correct commentary.

              This problem is hardly unique to computer science or programming. If your objective is to neither learn nor teach, but instead to be a dick, definitions are a great place to start.

              1. 2

                You’re right.

                Nomenclature isn’t a problem when trying to learn how to work for people who generally want to learn. But nomenclature can be a problem in communication, for the technically-correct, the idiosyncratic, the smart-enough-to-have-an-opinion-but-dumb-enough-to-derail, etc.

                1. 1

                  I’ve seen a lot of misuse of List in Scala because people (reasonably) assume it means the same thing it means in Java. Everyone understands once they’re told about it; the trouble is that you don’t know what you don’t know.

                  There are bigger problems, certainly, but it’s not a non-problem.

              2. 4

                Weak typing means that values can implicitly change type to fit operations performed on them. JavaScript is weakly typed: 5 + “3” will implicitly convert the string to a number and produce 8. Also, C is weakly typed: you can just straight up assign “8” to an int and get some hilarious nonsense.

                Hmm, these are two different things. The former is implicit conversion; the latter is weak typing.

                So yeah, naming is hard. Which was the real point, of course!

                1. [Comment removed by author]

                  1. 3

                    I think what you are trying to say is that the semantics of “weak typing” (which is a ridiculous, and meaningless term given the lack of formal, agreed upon definition) in JavaScript uses implicit conversion to, and this is the technical term for it, be all willy-nilly with assigning a type to a variable, or operand.

                    C has different semantics for its “weak typing.” While it’s easy to cast values into other types with no compiler errors, the amount of “implicit” conversions done is limited to like types with different widths, eg, using a char as an int, or similar. You’d have to cast a float int an int, at which point it is no longer implicit.

                    Implicit conversions aren’t weak typing. But, weak typing might be a classification based on the use of implicit conversions in a language. Scala, fwiw, has a concept of implicit conversions, but is considered “strongly typed” (the same ridiculousness for the term is assumed).

                    1. 2

                      Almost.

                      In javascript 5 + "3" the 3 is coerced/parsed to the number 3, so this becomes 5 + 3.

                      Whereas in C int a = "8"; is (probably [1]) re-interpreting the bits from the pointer to the string constant “8” as an integer.

                      Although I will also mention that in C you often need to make this cast explicit, at which point you are opting out of the type system (for the most part).

                      The better C example would be int a = 'c'; which is using the internal representation of a character as an integer, instead of converting.

                      There are small differences between conversion/coercion and casting,

                      In coercion you take something of type A and convert it to B, In casting you treat the value of something of type A as though it were already of type B.

                      [1] probably a reinterpret_cast, although I don’t think this is guaranteed to be the case.

                      1. [Comment removed by author]

                        1. 2

                          In coercion you have a value tagged as type A, you convert it to type B and then retag it - maybe with a copy - that is you convert values to make the types make sense.

                          In weak typing you either pretend the tag is never there, or you retag it as B as though it had been that way all along - this is you ignore or munge types as needed, without touching the values.

                          You can think of coercion (with strong typing) as being something like

                          def plus(Any a, Any b) -> Integer {
                            Integer aa = a.toInt()
                            Integer bb = b.toInt()
                            return aa + bb
                          }
                          
                          plus(5, "3") # will actually convert "3" into an integer
                          

                          This assumes you have a subtyping relationship that allows this.

                          All conversion/coercion happens at the value level.

                          I think of weak typing (with no coercion) as more

                          def plus(Integer a, Integer b) -> Integer {
                            return aa + bb
                          }
                          
                          plus(5, "3") # pretends "3" is really an Integer - god knows how
                          

                          In the later case the value within “3” may never have been consulted, all conversion/coercion happens at the type level. Think reinterpret_cast<String, Integer>

                          Although all these definitions being used are poorly defined.

                  2. 3

                    Unsolvable, too!

                    1. 4

                      Someone who’s asking whether X language is by-value or by-reference has likely ingrained the C model, and takes for granted that this is how programming fundamentally works.

                      Uh…the C model is how programming fundamentally works. Unless you’re on a non-von Neumann computer of some kind.

                      It seems to me a lot simpler just to admit that “Java, Python, Ruby, Lua, JavaScript, and countless other languages” of their ilk have pointers. Of course they do. How else do you think they work?

                      Haskell, on the other hand, really doesn’t seem to have pointers. Graph reduction is cool. :)

                      1. 17

                        It seems to me a lot simpler just to admit that “Java, Python, Ruby, Lua, JavaScript, and countless other languages” of their ilk have pointers. Of course they do. How else do you think they work?

                        I’ll bite. No. Pointers are an abstraction over what is happening at the machine level: there’s a memory location that holds a value and the value represents another memory location. Your processor doesn’t dereference. Your C compiler knows how to instruct the processor to do the things it calls “dereferencing”. Ruby has no concept of a pointer and a dereference, too, and just because some Rubies are implemented in C doesn’t mean that it has pointers. They have a concept of memory access, sure, but just because some of them follow some of the pointer semantics of C doesn’t mean they use Pointers as a programming concept.

                        Most programming is not the task of explaining the machine exactly what to do. It is the process of telling an intermediary (the compiler, the interpreter, the VM) of what to do and instruct the processor to do so. The intermediary usually applies non-complex transformations to your input.

                        C is not how programming fundamentally works. It’s just an intermediary that gives you rather direct access to the underlying machine.

                        1. 5

                          Could you clarify what you mean by your processor doesn’t dereference? How would you call mov eax, [edx]?

                          1. 10

                            A move. It’s fundamental to implement to C dereferencing, but that doesn’t make it the same.

                            1. 2

                              Perhaps I was misinterpreting gregnavis, but I assumed ey was referring specifically to the [edx] part of that instruction; which, if I have not forgotten everything about assembly at this point (a distinct possibility), is functionally storing the value in edx (a dereference) into eax.

                              Is that an incorrect characterization (genuinely asking; asm is not my forté)?

                              1. 9

                                Dereferencing a pointer in C is not the same as an indirect move.

                                @tedu even had a blog post recently, noting some pains in the misunderstanding that.

                                C pointers have semantics and rules. Very different ones than the mov instruction.

                                1. 3

                                  C pointers have semantics and rules. Very different ones than the mov instruction.

                                  True, but at the lowest level the derefencing is ultimately still done by the CPU. And by dereferencing I mean, “accessing memory that’s at an address stored in a register”.

                                  Or will a pointer derefence in C not ultimately be translated into an effective address mov (it’s been a while since I looked at this stuff)?

                                  1. 8

                                    If, when you say dereferencing, you mean “accessing memory that’s at an address stored in a register,” then you aren’t talking about dereferencing in C. @skade’s post carefully demarcated dereferencing (a C concept) from what actions the processor performs.

                                    No, a pointer dereference in C will not necessarily be translated into an effective address mov.

                                    1. 6

                                      Yes, good point (and reading a bit further, I’m reminded of the difference - my memory was a bit rusty, no pun intended!). I think I was focussing too much on Your processor doesn’t dereference in isolation rather than in the context of @skade’s entire post. Mea culpa.

                              2. 1

                                I’m sorry for being imprecise. I was thinking about the [edx] part. Having read the conversation below, I understand that what you’re saying is: dereferencing is a concept in the abstraction layer above the CPU and its semantics make it likely that the compiler will use [edx] et al. to implement it. Is my understanding correct?

                            2. 2

                              I can’t speak to Ruby (though if it’s like any other piece of semantics, they’re equivalent), but Python certainly does have pointers conceptually, albeit (like most languages that aren’t C) implicitly:

                              >>> l = []
                              >>> def foo(x):
                              ...     x.append(5)
                              ... 
                              >>> foo(l)
                              >>> l
                              [5]
                              

                              I don’t really care what you call it, but foo modified the state of its calling scope; there’s action-at-a-distance going on there.

                              1. 8

                                I think the term for “an implicit pointer” like that is “a reference”.

                                1. 4

                                  I think the term is not well defined, this being the thesis of the article and the basis of pretty much this entire thread of discussion.

                                2. 5

                                  But l doesn’t need to hold a pointer (the addressing method of python is not part of the language scope, and probably differs based on the type of l). Also, depending on which kind of runtime you use below, the address might change between your call and the return (some garbage collectors move around values). In Python, you don’t have access to the thingy that makes sure the list is found.

                                  Pointers as a programming concept are fundamentally about knowing the memory location and addressing method and knowing that the value won’t move away. In many modern programming environments, that isn’t an assumption you can make. Especially in JIT environment, you cannot even assume that there is a function call happening. You can’t even assume that just because a function call happened, a future one will happen under the same conditions.

                              2. 7

                                Uh…the C model is how programming fundamentally works. Unless you’re on a non-von Neumann computer of some kind.

                                I don’t think this is an accurate statement, but it depends on what “programming” means. That is fundamentally how von Neumann machines work, but one doesn’t necessarily program against a von Neumann machine even if it ends up running on one in the end.

                                1. 7

                                  The greatest trick that C ever pulled was convincing the world that it doesn’t have a runtime.

                                  1. 1

                                    For several definitions of a runtime, it doesn’t :). This is such a fun topic :D.

                                    1. 1

                                      Which definitions? I like /u/robgssp’s post about this.

                                      You could argue that C’s runtime is whatever host OS you execute C code on. Stuff like malloc is typically expected to be provided by that environment.

                                  2. 6

                                    That’s not really fair: C captures part of the ideal Von Neumann computer, but there’s plenty it doesn’t. In particular, it’s pretty rigid with control flow in that it mandates a call stack, and it doesn’t specify what that call stack looks like. This means that it can’t represent things like tail-recursive programs (barring nonstandard optimizations), garbage collection, or the nonrecursive procedures you see in older languages. Also since the code size of each statement isn’t specified, you can’t do things like roll your own jump tables; you have to rely on the limited switch/case construct. Also, you can’t write new programs in memory, which is one of the Von Neumann architecture’s more important aspects. Maybe this all is nitpicky, but I think if you start looking at the Von Neumann architecture as “what C does” you miss a lot of interesting bits.

                                    Also, Haskell totally has pointers. What else is an IORef? :)

                                    1. 2

                                      Word up. It’s like, if C was it, then why do we even still have assembly? Or inline assembly?

                                      1. 2

                                        Well, I’m not sure the existence of instructions like rdtsc and cpuid which can’t be accessed from C disproves the theory that C semantics are a good model for how computers work.

                                        1. 1

                                          “A good model for how computers work” != “fundamentally how programming works” though.

                                          1. 2

                                            No? Isn’t programming making a computer work? I wrote some code, the computer does something. There seems an obvious correlation between the two.

                                            1. 2

                                              I think that to me, it’s about the strength of the assertion. “pretty good” is not the same as fundamental. I agree that there’s a connection, but it’s juts a connection, not an equivalence.

                                              1. 1

                                                Attaching too much weight to the word fundamentally? Would “basically” be more appealing?

                                                1. 3

                                                  Reminds me of how TCP is a useful abstraction over the lower layers of the internet, but not a perfect and all-encompassing one. I wouldn’t say that “TCP is the foundation of the internet”, but I would say “TCP is generally pretty good for most people doing internet programming”.

                                                  C’s universality is helped by the fact that OSes and even processor architectures have been designed around it’s four-decades-and-counting existence.

                                                  At college, my professors always laughed when someone called C “a low-level language”. To them, having worked at Xerox, DEC, and other big computing corporations in the 70s/80s, C is a rather high-level language. However it does a fantastic job of straddling the boundary between high and low.

                                      2. 2

                                        The C model of pointers is how von Neumann computers work with pointers.

                                        The assertion was about by-value vs. by-reference parameters, not the entire C standard!

                                      3. 3

                                        Uh…the C model is how programming fundamentally works. Unless you’re on a non-von Neumann computer of some kind.

                                        Nah, not really. C is mostly about the calling convention and stack.

                                        1. 3

                                          Trying to find 100 different words to distinguish every implementation detail (“No, a pointer is a bit-pattern representing the signals to be placed on the address bus of the L1 translation lookaside buffer!”) obscures the commonality that all those languages have.

                                          I prefer to say that the languages mentioned have two kinds of value: immediates (small immutable things like integers) and pointers (references to possibly-mutable objects). Variables and object slots are bound to values. Understanding the semantics of those languages in those terms works fine, has a long history, and is even (usually) accurate to the implementation. Which is great because those are all languages known for their pragmatism, not their theoretical beauty. So I say keep it simple.

                                          For some contradictory examples: In Smalltalk everything, even an integer, is a pointer. Smalltalk implementations will do things like pre-allocate the integers from -100 to 100 for efficiency, which would be a nonsensical statement in the languages above. In Haskell, the concept of a pointer really doesn’t seem to exist. Variables are bound to nodes of an expression graph, which is a whole different idea.

                                          BTW, when I say the “C model is how programming fundamentally works”, yes, I’m talking about [edx]. That is, the thing 99.9% of C programmers assume the C semantics translate to in reality (and if you aren’t worried about reality, why on earth would you use C?). Instruction sets really do have a concept of pointers and they really do dereference them.

                                          1. 5

                                            BTW, when I say the “C model is how programming fundamentally works”, yes, I’m talking about [edx]. That is, the thing 99.9% of C programmers assume the C semantics translate to in reality (and if you aren’t worried about reality, why on earth would you use C?). Instruction sets really do have a concept of pointers and they really do dereference them.

                                            Why do you believe this, in rejection of both evidence given by other posters and the C spec itself?

                                            Even if 99.9% of C programers “assume” that about about C’s semantics, the reality would be that 99.9% are also wrong. Their belief has no impact on reality.

                                            1. 2

                                              Many processor instruction sets include something like [edx], sure (though the extent to which the x86 instruction set is “how it really works” is pretty limited on a modern processor). But treating this as some kind of fundamental truth about processors or about C is placing undue importance on it. Many processor instruction sets include things that can’t be represented in C, and conversely C can be compiled for stack machines that don’t have any equivalent of [edx].

                                              The C model is a useful model for modelling certain things, and can be efficiently expressed on many popular processors. That doesn’t mean it’s “how programming fundamentally works” any more than the fact that processors have an add instruction and PHP has a + operator means that the PHP model is how programming fundamentally works.

                                              1. 1

                                                The PHP model of + can add an integer to a string representation of a floating point number. There’s no processor that can do that. The C model of pointers (& and *) maps directly to any processor that has byte-addressable memory and indirect addressing.

                                                If we are now in a world where it’s not common sense that the C model of pointers maps directly to the processor model of pointers on any non-niche processor, I’m truly baffled. And I, at least, think it’s meaningful to say that how the processor works is how programming “fundamentally” works.

                                          2. 1

                                            Relatedly, I love to see “spelled” use to explain how to write code (especially a single construct or brief expression). Indexing is spelled a[b], etc.

                                            I hate this with a passion. It implies a well-defined, 1:1 correspondence like that between spoken and written language which doesn’t reflect reality. Even worse when people use “pronounced” to mean the converse.