Argument scope

A

Andreas Leitgeb

Mike Schilling said:
I'd guess it's a C or C++-like struct: an object all of whose fields are
public....

In the context of this group, "struct" has been used for a (proposed)
compound of fields that doesn't reside on heap, but *somewhere else*
(such as on the stack with all the logical consequences on its lifetime).
 
B

BGB

I'd guess it's a C or C++-like struct: an object all of whose fields are
public. (In C++, that may be a default rather than a uniform rule. I
honestly don’t recall.)

except, in this case, I was thinking more C# style struct semantics, as
these would likely be a better fit for Java.

so, the basic description is, it is like a class, except:
it is pass-by-value vs pass-by-reference;
inheritance is not supported;
methods may be supported;
....


an example:
struct Foo
{
public double x, y;
}

Foo a=new Foo();
Foo b;

a.x=3;
a.y=4;
b=a;
b.x=5;

now: a.x=3, a.y=4, b.x=5, b.y=4.


mostly, structs would allow potentially higher performance with some
operations (particularly vector math), since the use of pass-by-value
semantics allows the compiler and VM to more accurately know the
lifespan of objects (vs with classes where the lifespan is potentially
unbounded, and the VM can't statically optimize for the lifetime of any
object which may be potentially captured externally during its lifetime).

there is no need to handle the possibility of capture with a struct,
since it is always passed by value, so anything captured in a variable
is necessarily a copy.


C# also supports passing-by-reference with structs, but at this point
one almost may as well just use classes. in this case, I will also
ignore the possibility of supporting pointers (these would complicate
matters and constrain the implementation).


similarly, properties:

class Bar extends Object
{
private double x, y;

public double X {
get { return x; }
set { x=value; }
}

public double Y {
get { return y; }
set { y=value; }
}

}

which could internally expand to something like:
class Bar extends Object
{
private double x, y;

public double get_X() { return x; }
public void set_X(double value) { x=value; }

public double get_Y() { return y; }
public void set_Y(double value) { y=value; }
}


the main difference is that one can access a field differently:
Bar obj;
double x;

....
x=obj.X;
obj.X=3;

vs, say:
x=obj.getX();
obj.setX(3);


yes... properties are basically just syntax sugar...
 
B

BGB

In the context of this group, "struct" has been used for a (proposed)
compound of fields that doesn't reside on heap, but *somewhere else*
(such as on the stack with all the logical consequences on its lifetime).

yes, what I was thinking would be similar, just focusing primarily on it
being pass-by-value and having a constrained lifetime.

in this case, where it is stored is a secondary issue:
on the stack works (and is a very sane implementation).


on the heap is also possible, but with a few exceptions:
its lifetime remains finite, and it can be readily destroyed (without
having to wait for the GC to do its magic).

an example of the above could be if the struct were handled in a more
"malloc/free" like manner (vs being created and reclaimed some
indeterminate time in the future).

however, an efficient VM would likely just use the stack, since stack
space is allocated and destroyed very quickly.


the issue with normal objects is this:
a naive implementation can't know that they have gone out of scope and
are no longer useful (and have become garbage);
static object scope analysis is problematic and is of limited
effectiveness (all of the code needs to be visible, and any object
potentially captured may be preserved, which is a lot more than may be
actually captured);
naively dividing object references into local and global may itself risk
a number of "false positives", resulting in garbage being leaked onto
the heap, or create some overhead to handle this more precisely
(detecting if the local objects were only referenced by other local
objects and so may be safely freed, or if the local objects may in-fact
be safely freed).

having objects with statically known lifetime simplifies the task of
eliminating them earlier, and thus avoiding potentially notable delays
sometime in the near future.


or such...
 
A

Andreas Leitgeb

Peter Duniho said:
All parameters in Java are passed by value. See my other reply.

Indeed, but, unlike objects, structs *could* be passed.
It's not sane when you declare a value type member within a reference type.
...

This makes no sense at all to me, so I guess I just fail to
understand what you meant. Maybe it's a consequence of you
having a different picture of the proposed idea.

My picture of structs would be, that it is mostly a compiler thing.
Declaring a struct would mean declaring a set of variables that are
subsumed with a "meta"-name:
struct Z { int x; double y; } would mean, that whenever I use a
Z-typed variable "z", then the compiler inserts two variables
"z.x" and "z.y". If I make an assignment to z, the compiler would
make individual assignments for z.x and z.y (modulo further optimi-
zations). If a method takes a Z-typed argument, it really takes an
int and a double (each of which, and thusly also the struct, would
have pass-by-value semantics).
 
B

BGB

Hopefully, if Java does gain such a feature, they are more careful about
the "pass-by-reference" terminology.

Java doesn't have pass-by-reference, and classes (reference types) in
C#/.NET are passed by _value_ by default. Whether something is passed by
reference depends not on the data type, but on whether the "ref" or
"out" keyword is present. Both reference and value types are passed by
value without either of those keywords, and by reference with either of
them.

well, ok, this is arguing semantics...

I was not writing here about 'ref' or 'out'...


I was thinking of passing objects by reference or by value, not passing
variables or arguments.


if one wants to call them reference-types or value-types instead, either
way.

And lest anyone get all indignant and start a whole argument about the
question, I'll include a reminder that we've all already been there,
done that.
http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/cb4d31b429fdb02a/


Twice:
http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/2b8704996edfbf46/


Well, actually…lots more than that. But those are the most recent major
threads on the topic.
http://groups.google.com/groups?q=group:comp.lang.java.programmer+"pass+by+reference"



The main thing that value types provide is value type semantics. That
is, copy-value-on-assignment rather than copy-reference-on-assignment.
It's as much a program semantics thing as anything else, and allows
things like a primitive integer type that still inherits from the type
system's base class (System.Object in .NET, of course would be
java.lang.Object in Java), and easily copying the value of some data
structure.

well, that is another way of seeing it.

It can also be a performance boon, especially when it comes to storing
data structures in arrays, or maintaining them in local variables that
wind up being allocated on the stack. But at least in .NET, those are
implementation details, unlikely to change but not guaranteed either.

Unfortunately, many people have confused "value type" in .NET with
"always allocated on the stack", which of course is not true. Value
types _may_ be allocated on the stack, but then there's a language
keyword that allows reference types to be allocated there as well, and
of course value types wind up in the heap if they are allocated as part
of a reference type (e.g. an element in an array or a field in a
reference type). It's a mistake to conflate allocation strategies with
the value- and reference-type distinction.

yep.

well, one could also say "a contiguous block of bytes stored somewhere",
but this need not necessarily be the case either (if it is nowhere in
direct visibility of pointers or of C, it doesn't matter how exactly the
memory is organized, although a contiguous glob of bytes does make some
sense).

[...]
C# also supports passing-by-reference with structs, but at this point
one almost may as well just use classes.

C# supports pass-by-ref with both value types _and_ reference types, and
by default uses pass-by-ref with neither.

more semantics...

nevermind me and terms and words, grr...

[...]
similarly, properties:

class Bar extends Object
{
private double x, y;

public double X {
get { return x; }
set { x=value; }
}

public double Y {
get { return y; }
set { y=value; }
}

}

Yeah, I tried explaining the pleasures of properties here awhile back.
It apparently turns out to be one of those things that, if you haven't
used it, seems like something ridiculous to add to the language (though,
admittedly I have seen the same reaction to value types as well).

Suffice to say, those are just a couple of features in C# that, in spite
of how much I do like Java, cause me to strongly favor C# any time I
have the choice of language to use.


yeah, in some ways I like C# more as a language, and a few other things
were done fairly well, but have found I am a bit less of a fan of the
..NET VM as a whole...


meanwhile, I develop my own obscure piece of VM technology, but it is
more of an ad-hoc mess in some ways...

it does support JBC though (and currently the use of standard Java
compilers is my sole means of supporting Java), although it is unlikely
I will have full J2SE support anytime in the near future (the current
aim is for J2ME conformance).

but, I also want my freedom to pursue various implementation and design
options, which is harder with a more "frozen" piece of technology...

a goal will be to also possibly allow some of my other supported
languages to work on JBC (as opposed to each having their own local
bytecode formats and being multiplexed via the VM's core systems). but,
this requires finding good ways of making a lot more features work
through it (and addressing a few of its limitations, ...).


yes, yes, in the end it will probably all amount to nothing, but really,
why does this *always* have to be the concern...

why can't a person just do their own thing and accept full well that it
will probably just amount to nothing in the end anyways, and that
neither change nor relevance matters? (or, maybe, that beyond what one
gets out of it, change may be more of a necessary evil than anything
else... like the lyric "I don't want to change the world, but I don't
want the world to change me...").


but, alas...
 
B

BGB

Indeed, but, unlike objects, structs *could* be passed.


This makes no sense at all to me, so I guess I just fail to
understand what you meant. Maybe it's a consequence of you
having a different picture of the proposed idea.

My picture of structs would be, that it is mostly a compiler thing.
Declaring a struct would mean declaring a set of variables that are
subsumed with a "meta"-name:
struct Z { int x; double y; } would mean, that whenever I use a
Z-typed variable "z", then the compiler inserts two variables
"z.x" and "z.y". If I make an assignment to z, the compiler would
make individual assignments for z.x and z.y (modulo further optimi-
zations). If a method takes a Z-typed argument, it really takes an
int and a double (each of which, and thusly also the struct, would
have pass-by-value semantics).

well, although I see this as a possible implementation, I personally
feel that such an implementation strategy is overly constraining, and
would admittedly rather see them supported at the VM level than simply
at the language/compiler level.

hence, my considered implementation strategy takes a somewhat different
form (namely, identifying classes as being structs and adding operations
to facilitate preserving their semantics regardless of proper VM
support), rather than thinking in terms of how to manage a glob of
variables.

in this later form, the VM would be responsible for finding an efficient
way to store and work with them.


or such...
 
A

Andreas Leitgeb

Tom Anderson said:
BufferedWriter out;
with (out) {
write("foo");
newLine();
write("bar");
newLine();
}
Which basically redefines the implicit target of invocations inside its
scope from 'this' to something else. It's a little wordier.

Pascal had it already. I learnt Pascal before I got in touch with C,
and bemourned the lack of "with" in C. I'd love to finally see it at
least in Java :)
A construction which i hate with a burning passion.
...
How does that have any semantic meaning?

semantic meanings are overrated :)

PS: there's also:
BufferedWriter _ = ...;
_.doThis(); _.doThat(); ...
or, using short names like "b", or "bw".
 
A

Andreas Leitgeb

BGB said:
I was thinking of passing objects by reference or by value, not passing
variables or arguments.

Oh, prepare to be flamed for that.

It's really just a language nitpickery.
By using the terms "pass" and "reference" together, you implicitly
have switched from Java-speak to "technical term"-speak, where a
reference is something different from Java's so-called references.

In "technical term"-speak, however, objects aren't "passed" at all -
instead "references" (hmm, shouldn't that be "pointers", then?) are
passed, obviously by value.

I'd really like to know a Java-term to be used instead of "to pass",
such that it would be allowed to say "An object (or possibly none)
is *coffepot* to this method by (Java-)reference."
 
S

Stefan Ram

Andreas Leitgeb said:
In "technical term"-speak, however, objects aren't "passed" at all -
instead "references" (hmm, shouldn't that be "pointers", then?)

I already posted this many times before:

»(...) reference values (...) are pointers«

JLS3, 4.3.1.
 
A

Andreas Leitgeb

well, although I see this as a possible implementation, I personally
feel that such an implementation strategy is overly constraining, and
would admittedly rather see them supported at the VM level than simply
at the language/compiler level.

I see your intention. I just do not believe that it would work out in
a useful way.
 
A

Andreas Leitgeb

Stefan Ram said:
I already posted this many times before:
»(...) reference values (...) are pointers«
JLS3, 4.3.1.

Ok, that addresses my parenthesized side-comment, but not the rest of
my post.
 
L

Lew

except references, which are the value of the reference.

Actually, that's *including* references, whose value is a pointer.

This is a question I got wrong the first time I took a practice Java test.
All parameter passing in Java is pass-by-value. Period. Passing a reference
by value is not the same thing as passing by reference.
well, then presumably the value-type is inlined within the class or
similar, rather than being placed on the stack. this is no big issue.

Currently, in the present, likely on your very computer, the (commercial) JVM
(at least in "-server" mode) will inline some things, enregister others, and
convert references into stack-based primitive values. It's already doing the
implementation strategies that have been mentioned here.
...
in my VM at least, garbage objects can easily end up sitting around for
many minutes or more with the GC never realizing that they have become
garbage (my GC basically just uses concurrent mark/sweep, and garbage
will usually sit around until whenever is the next GC pass).

Currently, in the present, likely on your very computer, the (commercial) JVM
supports a number of GC strategies that address the issues you raise, all
important issues in the GC world.

There are a number of white papers related to the subject available on the
Oracle, erst Sun, site.

The generational strategy deployed by default doesn't require the GC to
"realize that [objects] have become garbage". True, collected objects may
never be finalized or released, but that's only if they needn't be.
Otherwise, GC only cares about live objects for the most part, and for the
most part in an idiomatic Java program those constitute somewhere around one
in twenty.

Java's GC is triggered by a need for memory rather than an observation of end
of life for some objects. Also, Java offers a smorgasbord of GC
implementations to leverage, say, multi-core platforms.
 
L

Lew

Peter said:
It [value types] can also be a performance boon, especially when it comes to storing
data structures in arrays, or maintaining them in local variables that
wind up being allocated on the stack. But at least in .NET, those are
implementation details, unlikely to change but not guaranteed either.

Unfortunately, many people have confused "value type" in .NET with
"always allocated on the stack", which of course is not true. Value
types _may_ be allocated on the stack, but then there's a language
keyword that allows reference types to be allocated there as well, and
of course value types wind up in the heap if they are allocated as part
of a reference type (e.g. an element in an array or a field in a
reference type). It's a mistake to conflate allocation strategies with
the value- and reference-type distinction.

Not only that, but the JVM allocates on the stack already, including reference
types. So it's a mistake to to conflate those concepts even within the Java
universe.
 
B

BGB

Actually, that's *including* references, whose value is a pointer.

This is a question I got wrong the first time I took a practice Java
test. All parameter passing in Java is pass-by-value. Period. Passing a
reference by value is not the same thing as passing by reference.

fair enough...

Currently, in the present, likely on your very computer, the
(commercial) JVM (at least in "-server" mode) will inline some things,
enregister others, and convert references into stack-based primitive
values. It's already doing the implementation strategies that have been
mentioned here.
...

ok, the question then is the best way to determine this statically.
an issue at the moment is that my OO system and JVM-related components
are in different libraries/subsystems, and so the level of inferences
are a little more limited here.


as a general rule, the OO facilities don't even assume that object
layout is frozen (the ability to change object layout at run-time is
supported, with each object identifying the particular version of the
class which created it).

an example would be adding some new fields to a base-class, which
involves reorganizing all derived classes, which can cause all
subclasses to take on new versions (new objects then have the new
layout, but old objects keep the old layout).

a little performance is paid for this though (freezing layout for
certain classes would allow further optimizing things like field access
and method dispatch).

in my VM at least, garbage objects can easily end up sitting around for
many minutes or more with the GC never realizing that they have become
garbage (my GC basically just uses concurrent mark/sweep, and garbage
will usually sit around until whenever is the next GC pass).

Currently, in the present, likely on your very computer, the
(commercial) JVM supports a number of GC strategies that address the
issues you raise, all important issues in the GC world.

There are a number of white papers related to the subject available on
the Oracle, erst Sun, site.

The generational strategy deployed by default doesn't require the GC to
"realize that [objects] have become garbage". True, collected objects
may never be finalized or released, but that's only if they needn't be.
Otherwise, GC only cares about live objects for the most part, and for
the most part in an idiomatic Java program those constitute somewhere
around one in twenty.

Java's GC is triggered by a need for memory rather than an observation
of end of life for some objects. Also, Java offers a smorgasbord of GC
implementations to leverage, say, multi-core platforms.


I use my own implementation so that I have complete control over the
implementation (and freedom to tinker around with the internals, try out
new ideas, ...), nevermind if it is slow or otherwise crap.

I use the Sun/Oracle JVM for other things though.


but, yeah, mine may be triggered either by running out of memory or
exceeding a threshold (around 70% of heap used). where it will try to
run the GC and hope the app doesn't notice (although, sadly, there is no
good way to handle allocations mid-GC, since the GC is mostly busy doing
its mark/sweep thing). otherwise, it would require either "emergency
back-up memory" which is safe to allocate during the GC, or interrupting
the GC in order to perform memory allocation tasks.


but, it is not a copying or generational GC, as these tend to conflict
with using the same GC for C code (the main use of the GC is actually
for stuff in C land). as a result, it is a conservative non-moving GC.

internally though, it does have some support for precise marking, ...
just no memory compaction or similar.


otherwise, I would have to use a different GC for HLL's than for C,
which has been done in the past, but this style fell into disuse mostly
because it tends to make things more awkward (and a concurrent precise
GC means much pain in registering and unregistering roots, which is
unreasonably awkward apart from explicit compiler support).

similarly, my current GC also allows optionally using reference-counting
(in addition to mark/sweep), but reference counts have the great
complexity of actually updating them correctly everywhere they are used,
which is unworkable in "C in general", limiting use mostly to controlled
areas.

ref-counting is done per-object (actually, it is technically used on all
objects, except that the default allocation mode has the ref count set
to 'many', effectively disabling the ref-count).


in general, the main optimization is to use it more like it was a
malloc/free allocator, where objects can be freed as soon as they are
known to be no longer be needed.

otherwise, the garbage sits around until the next time the GC runs, thus
preventing the same memory from being used for other stuff.


some other pieces of code optimize things by running their own local
MM/GC systems, usually operating under the "fill memory and discard
everything when done" model, which is faster, but any output has to be
manually copied out. this strategy is thus far mostly limited to
compiler-related components, as these tend to produce a lot of garbage
fairly quickly (and don't mix well with the main GC).


or such...
 
B

BGB

Oh, prepare to be flamed for that.

It's really just a language nitpickery.
By using the terms "pass" and "reference" together, you implicitly
have switched from Java-speak to "technical term"-speak, where a
reference is something different from Java's so-called references.

ok, but one can also assume that since Java lacks C++-style references,
this issue can be ignored.

given that pretty much no modern language I am aware of uses "pass by
reference" in its traditional sense, presumably this can be ignored.

In "technical term"-speak, however, objects aren't "passed" at all -
instead "references" (hmm, shouldn't that be "pointers", then?) are
passed, obviously by value.

or, one could just use the term "handle" instead, saying "an object is
passed by handle".

I guess, the issue with "pointer" is that it implies the language having
explicit pointers and pointer semantics (like in C). rather than the
"opaque pointer-like things" which are commonly called "references".

but, yeah, an issue came up recently elsewhere with a video with Tony
Hoare, where apparently the terms pointer and reference were used
largely interchangeably.


in my VM core, the term "reference" is mostly used for opaque pointers
mostly used to reference objects (originally, declared in C as "void *",
but I switched them to being an incomplete struct type mostly to help
detect unsafe implicit casts).


many other VM types exist in C land as opaque struct pointers where the
struct body is only defined within the library which contains the code
(this being used as a way of doing something analogous to "private").

generally, one doesn't want to give code existing in other components
access to internal parts of objects or data structures (also, separating
internal and external functions, types, structures, ... also helps make
the compiler go faster via having to not process as much stuff).

most interfacing is then done via API calls which pass these handles
around. (to some extent a lot of the API design was influenced by the
Win32 API and by OpenGL).


so, for example, the OO facilities have no direct visibility into the
GC, and the particular language VMs have no direct visibility into the
object system (nor does the object system know about the particular
language-specific VMs which use it).

some amount of dynamic typing is commonly used as well (a lot of this
stuff was mostly originally designed for dynamically typed languages
along the lines of Scheme and JS and similar).

note that, within the OO system, basically code in one language can
fairly freely call code written in another (be them compiled,
interpreted, or whether they use the same or different bytecode/IL).

the system also supports both Class/Instance and Prototype-OO semantics.


note that not a lot of this code is particularly new... (the codebase
goes back to the late 90s, and took form over time).


there are some drawbacks though...


I'd really like to know a Java-term to be used instead of "to pass",
such that it would be allowed to say "An object (or possibly none)
is *coffepot* to this method by (Java-)reference."

yeah...
 
L

Lew

or, one could just use the term "handle" instead, saying "an object is
passed by handle".

That wouldn't be accurate. As Andreas said, in Java "objects aren't 'passed'
at all". Using your language, "handles" are passed by value, but that's not
Java terminology. Whether you call references "references", "pointers",
"handles" or "fumingahoogilogagablaaddderroffroylichtensteiners", they are
what get passed in Java method calls, not objects.
I guess, the issue with "pointer" is that it implies the language having
explicit pointers and pointer semantics (like in C). rather than the
"opaque pointer-like things" which are commonly called "references".

"Implies" if you disregard the context, i.e., that it's the Java world. What
the word "pointer" *denotes* is what Java does. Regardless, that's why Java
mostly uses the term "reference", to avoid people insisting that the word
"pointer" must refer to C-style semantics instead of carrying its general meaning.
but, yeah, an issue came up recently elsewhere with a video with Tony
Hoare, where apparently the terms pointer and reference were used
largely interchangeably.

Because they're largely interchangeable concepts.
 
A

Arne Vajhøj

In the context of this group, "struct" has been used for a (proposed)
compound of fields that doesn't reside on heap, but *somewhere else*
(such as on the stack with all the logical consequences on its lifetime).

I can not imagine anyone suggesting a struct for Java with the
semantics of never being in the heap.

It has probably been suggested to get struct for Java with
the C# semantics of being a value type.

Arne
 
B

BGB

Could be C# style structs.

yeah.

this is mostly what I meant.

mostly, they seem like they would be a reasonable fit for Java in general.


I have noted thus far that there are several proposed ways to add them
being mentioned here. I may just implement them in my VM how I want to
implement them (unless anyone has any solidly better ideas).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,480
Members
44,900
Latest member
Nell636132

Latest Threads

Top