OT, but "ROOT" isn't a C++ interpreter. CINT (which is indeed part of
ROOT) is - or at least it is meant to be.
mind you, it started as a C -not C++- interpreter on top of which
C++ was bolted on. I let you imagine the "interesting" side effects of
such an approach...
cheers,
sebastien.
Lisp sits at 13 in the index today and their are definitely compiled
versions of that language with GC - if you can think of a way to
implement a programming language someone has probably implemented a
Lisp that way ;-)
--
Geoff Teale
Hi Serge,
I've been lurking in this mailing list for several months now but your
statement below caught my attention.
My last play with pointers is my college days 11 years ago, and been
programming business apps with Java/Python/Ruby since I graduated. I
love the philosophy behind golang and waiting for it to go mainstream
and be adopted in my company. But it's baffling to me that Golang is
not designed with implicit use of references as other languages are. I
admire Golang and the people behind it and it follows that I should
also appreciate the use of pointers versus the pass-by-reference that
I'm used to.
My experience and knowledge with languages is VERY limited so what's
baffling to me is surely explainable by someone knowledgeable and
enlightened. And since you mentioned this, maybe you could give me
some insights and educate me why you said "explicit use of pointers
instead of implicit use of references" is clearer.
Thanks.
An honest suggestion: stop talking publicly about language comparisons
and offering recommendations while you have no idea about how they
work whatsoever. Instead, spend that time actually using and learning
about them.
--
Gustavo Niemeyer
http://niemeyer.net
http://niemeyer.net/blog
http://niemeyer.net/twitter
This of course makes your life as a programmer far easier. You don't
have to remember what types are passed by reference, and what types
are passed by value. You don't have to find performance bottlenecks
that don't make sense (such as a user-defined integer being passed
around by reference, and constantly getting dereferenced). You don't
have to remember to indicate to send it by value, rather than
reference. You just send it. If you want to change the variable
directly, you send a reference. If you want to send it into the black
box, and get it transformed on it's way out, you send a value.
Also, all of this "pass-by" stuff is a bad paradigm. Programs have
pointers and values. The data is a pointer or value. If I have a
value, and I'm sending that value to a function, I want the value to
get there. If I have a pointer, and I'm sending it to a function, then
I still want the pointer to get there. I don't want anything getting
sullied up by the language between my variables and my functions,
except me.
In short: Go sends data, Java throws poop
In Java, non-native types are only represented by references, but
those references are always passed around by value. (There is a
specific computer-science meaning for "passed by reference" and
neither Java nor Go has it -- but C++ does.)
Go's pointers are rather like Java's implicit references. But Go
/also/ allows you to pass the actual values of structs (etc) around
as well as pointers to them. Once you can do that, trying to make
get-reference-to and de-reference implicit is tricky and probably
not worth it. (It can be done -- Algol 68 does it -- but the cost is that
it can be hard to keep in your head where theings are pointers and
where they're not. I Have Been Bitten.)
> Anyway, isn't it discouraged in Go to pass object or
> struct value to a function
No.
> especially if the struct is big,
If the struct is "big enough" there may be a performance optimisation
by passing a reference to it instead. Or it may be a performance
/pessimisation/ -- eg passing a reference means that it's pretty
certain (with today's Go compilers) that the struct will be heap-
allocated, and hence produce more GC load, while if it were passed
by value it might get away with stack allocation.
Measurement beats speculation.
> and that
> programmers and API designers would most likely require a pointer
> argument or return a pointer?
They might, or they might not. It depends.
> So, bottom line, my question is actually
> about the *implicitness* for usability's sake.
I don't see the explicitness of Go's pointers as presenting a
usability problem.
Chris
--
Chris "allusive" Dollin
> In short: Go sends data, Java throws poop
Omit needless words.
package main
type S struct {i int}
func (s *S) hello() {println("i =", s.i)}
func (s S) duh() {println("duh")}
func main() {
var s *S = &S{}
s.hello() // pass s as-is to hello
s.duh() // pass s dereferenced to duh
(*s).hello() // pass *s's address to hello
(*s).duh() // pass *s as-is to duh
}
?
I've never had a problem with it (except in a language which
did it implicitly ...).
To me this sounds like "keeping track of whether pants go on the top
part or the bottom part is a pain sometimes" as a justification for
making pants that automatically transform into a shirt when pulled
over your head.
Remembering you have/need a pointer is no more difficult than
remembering you have/need a slice. The only confusion can come from
intentionally ignoring this piece of information and instead thinking
in terms of the "pass by reference" vs "pass by value" dichotomy in
other languages.
> That's not quite right, Java always passes everything by value.
>
> You just never have anything but references to objects to work with,
> so the reference is passed by value and it's a copy of that reference
> received at the method being called.
Boxing.
--
Chris "allusive" Dollin
> It's the unnecessary punctuation that's really the painful part, not the
> keeping track. Apparently the Go authors felt similarly about unnecessary
> punctuation for message sends. Why not do it for all of the arguments
> instead of just the receiver?
It's particularly bad for the receiver. Methods on pointer types are
very common. For a while we were writing
(&v).M()
for almost every method call. It was awkward. A method call is already
distinctive enough that it seemed OK for the language to take the
address for you, so we could just write
v.M()
Passing arguments to functions seems different, at least to me. The
difference is that if you pass v to a function, you know that it will
not change. If you pass &v, you know that it might change. With a
method call, whether the value changes or not is a property of the
variable's type. With a function, it's being decided in some other
package far away.
This is not a conclusive argument, it's just a tradeoff, like all other
language decisions.
Ian
With the receiver, the added punctiation actually Is significant
because you have to use brackets. For the other arguments, all you
need is a single extra character at the beginning. It's not
comparable. With arguments, you have to be careful when it comes to
passing to an interface value. It's better to always need to be
explicit than to sometimes need to be explicit, especially when the
difference is one character. This problem doesn't exist for the
receiver.
This is semantically distinct/disjoint from the mechanism of a
conversion. It can be mistakenly perceived as interchangeable though
(i.e. as a conversion from T to *T). But there is no such conversion
in Go. Neither implicit nor explicit. To get an expression of type *T
from an expression of type T one must use the address operator ('&')
of a T instance or a type literal ('&T{}') or 'new(T)', not a
conversion.
The above specifications of the method sets just says that the
language/compiler will conveniently "insert" the address operator for
you in the same manner as it will done here, just in the opposite
direction:
type S struct{
f int
}
var v = &S{1}
println((*v).f) // manually
println(v.f) // here the '*' operator is "inserted" by the language/
compiler for convenience.
type Number *Number
var n Number
how would one distinguish assigning to n from assigning to the contents of n?
If that seems a silly example, it's just a form of
var p *int
x := p
Is x a copy of p, or a copy of what p points to?
* is an operator. It operates. It can't operate if it's not there.
There are a couple of places in the language where it's invisible, for
programmer convenience, but it's still there. Just ask the compiler.
-rob
If * were eliminated, given
type Number *Number
var n Number
how would one distinguish assigning to n from assigning to the contents of n?
If that seems a silly example, it's just a form of
var p *int
x := p
Is x a copy of p, or a copy of what p points to?
* is an operator. It operates. It can't operate if it's not there.
There are a couple of places in the language where it's invisible, for
programmer convenience, but it's still there. Just ask the compiler.
-rob
They make "pointers disappear" by not having a choice
between pointers and composite values; all (assignable)
structured values are dealt with using pointers to memory
which is (almost always) allocated from some heap.
It's not surprising that this difference shows up in the syntax
for accessing values.
The test case for me is, given that a and b are both *T,
what does
a = b
(or, equivalently, f(b) where f = func(a *T) {...})
mean? Whichever of "assign b to a" or "assign the
value b refers to to the place a refers to" it means,
how do you express the other one? The only answers
I've seen -- this is not the first time we've discussed
this issue -- either throw up their hands and say, well,
in that case we need special syntax/use * after all,
or try and break up the assignment/parameter passing
into smaller, disambiguated (, clumsy) chunks.
Given that you can't get the bump out of the carpet,
sticking with the existing, well-understood techniques,
for something that doesn't seem to be an actual problem
(the gains in expressiveness are IMAO small), seems
like a reasonable approach.
Chris
--
Chris "is the sentence finished yet? has it a VERB?" Dollin
> What I'm saying is that it seems like Go can generalize the dot operator's> boxing and unboxingNo boxing, no unboxing is done by the selector (dot) operator. The
automatic dereferencing of a pointer, when it appears with a selector,
is only a convenience providing the only sane semantic value of some
'p.field' whilst not aliasing/shading any other reasonable and/or well
defined meaning of it.
> having programmed for many years in C, C++, LISP,That surprises me.
> Smalltalk, Java, etc.,
>
> Go essentially allows pass-by-reference semantics for receivers only. For
> example, if you say p.meth(), where p is a struct
Nitpick (but an important one): where p is a /variable/ of some type T ...
> and meth is defined on pointers to that type
T
> of struct,
which need not be a struct.
> you haven't explicitly passed a pointer to
> p, but the method gets a pointer to it, which it can store somewhere else if
> it wants to, causing a change to the p struct from some other code at some
> other time (which is what you would expect from pass-by-reference, anyway).
> To me, this makes the dot operator fairly magical in a language that only
> has pass-by-value most other places.
Other nitpick: it's not the dot operator, it's the dot operator /used in a
method call/.
On 23 November 2010 16:05, Bill Burdick <bill.b...@gmail.com> wrote:Nitpick (but an important one): where p is a /variable/ of some type T ...
>
> Go essentially allows pass-by-reference semantics for receivers only. For
> example, if you say p.meth(), where p is a struct
package main
T
> of struct,
which need not be a struct.
Other nitpick: it's not the dot operator, it's the dot operator /used in a
> you haven't explicitly passed a pointer to
> p, but the method gets a pointer to it, which it can store somewhere else if
> it wants to, causing a change to the p struct from some other code at some
> other time (which is what you would expect from pass-by-reference, anyway).
> To me, this makes the dot operator fairly magical in a language that only
> has pass-by-value most other places.
method call/.
interpretation of the v.f() in a valid program above (i.e. by means ofWhat this means is - there is always one and only one possible
getting rid of one of the conflicting functions f()). For your
convenience the language specs and the compiler kindly allows you not
to write that awkward (&v).f() because, as can be seen above, it is
not ambiguous with only one method f() existing for type T which v
happens to by instance off.
In one sentence one more time - The selector (you call it the dot
operator) only selects and does no magic, no conversion, no pass-by
mode modification and the whole mistaken perceiving of it doing
something special is an unambiguous convenience of the language saving
you few keystrokes which *are semantically still there* and that's why
nothing magical is happening.