C# 3.0 new language features

J

Jon Davis

Barry Kelly said:
In many ways, I find that the arguments against 'var' strongly
reminiscent of the arguments in favour of hungarian notation. The
semantic meaning of the code should be visible by reading it.

I disagree. Visual Studio makes an inference at design time what a type
variable is and allows the coder to identify that type when hovering,
invoking dot-notation, or accessing its definition. Unless it's smart enough
to find this inference at design time (rather than at compile-time), this
immediate inference will be lost.

Jon
 
L

Lucian Wischik

y"S Chapman said:
(*!!*) Lambda expressions : listOfFoo.Where(delegate(Foo x) { return
x.size>10;}) becomes listOfFoo.Where(x => x.size>10);

I've been programming in functional languages a lot, where we use
these, and half the time they're unreadable and the other half they
make things enormously more clear. (how? mainly because the function
definition becomes local rather than at top level, so there are fewer
entities in your code, fewer top-level methods or functions).
(*!!*) Local variable type inference: var x = "hello"; is
interchangeable with string x = "hello";

Unreadable? I'd say the opposite. It'll be like Visual Basic and
Javascript, and wonderful. At the moment I write stuff like this,

SortedList<string,List<int>> x=new SortedList<string, List<int>>();

and it will become

(*!!*) Anonymous types : var x = new { Name = "James" }

I think this solves the horrid problem of object-oriented languages
that you can't return a tuple easily. If you want to write a function
that returns (int,int,string), i.e. a x-y coordinate and a label, then
you have to create a new struct/class. And wrap its fields up in
properties. And write a constructor. And provide an implementation for
Equals and GetHashCode and == and !=. And then construct it and assign
the fields. Yuck.

I actually did this in practice. I wrote my first prototype in F#, a
functional language, where I did return that (x,y,string) anonymous
tuple. And it took 1 line. Then I turned it into clean object-oriented
C# that obeyed FxCop and all the good programming practices of C#, and
it became 150 lines long.




So for all of these changes, I think they'll allow elegant concise
solutions to problems. Because they're more concise they have the
potential to be more readable. And they also have the potential to be
less readable. Good developers will use them in the first case, bad
developers will use them in the second case.

It'll maybe let Python programs program in C# more easily.
 
F

Frans Bouma [C# MVP]

Jon said:
I disagree. Visual Studio makes an inference at design time what a
type variable is and allows the coder to identify that type when
hovering, invoking dot-notation, or accessing its definition. Unless
it's smart enough to find this inference at design time (rather than
at compile-time), this immediate inference will be lost.

Always think ahead of what might be when you don't have your
super-duper helper tools available to read simple ascii code. If I
paste a piece of code in an email or blogpost, I'd like to have it to
be readable. This also speeds things up when reading code inside
vs.net. Because: do you hover over every variable in your code to
verify if it has the type you THINK it has? I bet you don't (as all of
us don't). It's human nature: "I think it has that type because <insert
assumed reason here>", as humans like to assume things.

That said, I don't think hungarian coding is the silver bullet for
giving that readability, as I've written large pieces of code in
hungarian coding style and after I've left it some years ago I haven't
really find myself wondering what type a variable is, basicly because
variable NAMES are more important and hungarian coding has a
disadvantage as well: what to pick for acronyms for variables of a
custom class type of along name (m_arrmecEntities ?? member variable
which is an array of MyEntityClass types. I don't think that's useful)

FB

--
------------------------------------------------------------------------
Lead developer of LLBLGen Pro, the productive O/R mapper for .NET
LLBLGen Pro website: http://www.llblgen.com
My .NET blog: http://weblogs.asp.net/fbouma
Microsoft MVP (C#)
------------------------------------------------------------------------
 
B

Barry Kelly

Jon Davis said:
I disagree. Visual Studio makes an inference at design time what a type
variable is and allows the coder to identify that type when hovering,
invoking dot-notation, or accessing its definition. Unless it's smart enough
to find this inference at design time (rather than at compile-time), this
immediate inference will be lost.

Another thing about var: it will help (ever so slightly) in writing a
form of generic code:

---8<---
var parts = GetCollectionOfStuff(x, y, z);
foreach (var part in parts)
{
Fiddle(part);
Frob(part);
}
--->8---

Here, the type of collection returned by GetCollectionOfStuff() may
change in the future, and if Frob() & Fiddle() also change, this
algorithmic code won't need to be modified.

I know, I'm stretching it a bit. However, a lot of working code has been
written in Python and Ruby, using dynamic typing, so I don't think that
eyeballing the source to see the semantic operations is much harder
without explicit type annotations. And this way, static typing is still
preserved.

I've always thought that the main argument for static typing is catching
errors at compile time, not for cluttering the code with the
implementation details of semantic quantities.

-- Barry
 
V

Volker Hetzer

S said:
In C# 3.0 there will be radical additions:
[lots of stuff I don't need]
Can it do MyObjectType X(MyConstructorparameters);
and create an object on the stack where I don't
have to do all this dispose stuff because the destructor
gets called as soon as it gets wiped off the stack?

Lots of Greetings!
Volker
 
B

Barry Kelly

Volker Hetzer said:
S said:
In C# 3.0 there will be radical additions:
[lots of stuff I don't need]
Can it do MyObjectType X(MyConstructorparameters);
and create an object on the stack where I don't
have to do all this dispose stuff because the destructor
gets called as soon as it gets wiped off the stack?

A struct implementing IDisposable and used inside a "using" block does
all you need.

-- Barry
 
V

Volker Hetzer

Barry said:
Volker Hetzer said:
S said:
In C# 3.0 there will be radical additions:
[lots of stuff I don't need]
Can it do MyObjectType X(MyConstructorparameters);
and create an object on the stack where I don't
have to do all this dispose stuff because the destructor
gets called as soon as it gets wiped off the stack?

A struct implementing IDisposable and used inside a "using" block does
all you need.
Actually no. IDisposable is not what *I* need, it's what
*every caller* of my objects "needs".
The point of the suggestion above is that I implement it once
and no caller can do it wrong anymore. Especially, the caller
should IMHO not have to differentiate between objects
and non-objects. With dispose he has to.

Lots of Greetings!
Volker
 
M

Martin Carpella

Volker Hetzer said:
Actually no. IDisposable is not what *I* need, it's what
*every caller* of my objects "needs".

You could always work around this problem by using finalizers. Of
course, finalizers have their downsides (e.g. all finallizable objects
are not created on generation 0 but generation 1 or 2 if I remember
correctly).

Best Regards,
Martin
 
B

Barry Kelly

Volker Hetzer said:
Actually no. IDisposable is not what *I* need, it's what
*every caller* of my objects "needs".
The point of the suggestion above is that I implement it once
and no caller can do it wrong anymore.

Even if you had C++ destructor semantics on automatic variables of type
struct, such structs could be allocated as a field in a heap-allocated
object - so the users of the class would still have to care.

The idiom in C# for C++ RAII is "using". If client code isn't doing
that, it's their problem. It's as simple as that.
Especially, the caller
should IMHO not have to differentiate between objects
and non-objects. With dispose he has to.

I don't quite understand what you refer to. Do you mean a distinction
between value types and reference types? Or between objects which
require disposal and those which don't?

-- Barry
 
V

Volker Hetzer

Martin said:
You could always work around this problem by using finalizers. Of
course, finalizers have their downsides (e.g. all finallizable objects
are not created on generation 0 but generation 1 or 2 if I remember
correctly).
Yes, that would often work, but as far as I know there's no guarantee
that the garbage collector gets called.
When you have to hand back a license token this is not nice.

Lots of Greetings!
Volker
 
V

Volker Hetzer

Barry said:
Even if you had C++ destructor semantics on automatic variables of type
struct, such structs could be allocated as a field in a heap-allocated
object - so the users of the class would still have to care.
I think a workable idea would be to have a reference to that object
on the stack (if it is declared locally). Then, when the runtime system
clears the stack, it knows that an object is a local one and can be
destroyed immediately. That way MS perhaps wouldn't have to break
much of their CLR.
The idiom in C# for C++ RAII is "using". If client code isn't doing
that, it's their problem. It's as simple as that.


I don't quite understand what you refer to. Do you mean a distinction
between value types and reference types? Or between objects which
require disposal and those which don't?
Both. I think the matter of disposal shouldn't depend on the internals
of an object but on the way of creation.
So, If I write myType X; I shouldn't have to look up what the type is
in order to figure out whether I need to do a X=new mytype(); too.
Somehow I feel more comfortable with C++'s way of letting the user decide
how he wants the object to be managed (automatically on the stack
or manually with new/free).
On the other hand, GC can be very fast, so maybe the best of both worlds
is a way to declare objects locally and have them managed deterministically
*and* a new/free where free calls the finalizer or dispose (if there is one).
Then one can lose the reference and gc takes care of the rest.

Lots of Greetings!
Volker
 
B

Barry Kelly

Volker Hetzer said:
I think a workable idea would be to have a reference to that object
on the stack (if it is declared locally). Then, when the runtime system
clears the stack, it knows that an object is a local one and can be
destroyed immediately. That way MS perhaps wouldn't have to break
much of their CLR.

But what if the object isn't local - what if it's added to a collection,
or passed to some other routine in another assembly, not visible at
compile time?

My point is that you can't force users to dispose of the objects, and
that the idiom for this requirement in C# is the "using" statement.
Both. I think the matter of disposal shouldn't depend on the internals
of an object but on the way of creation.

I can only agree to a limited extent. I think that it's fairly rare that
objects which are commonly allocated on the stack have implementation
changes that toggle whether or not they implement "IDisposable".

Database connections, file streams, windows (and thus controls), it is
obvious that these things, by their semantics, require disposal, since
they deal with persistent connections to things external to the
application's memory space.

If some object or component is so complex that one doesn't immediately
know whether or not it will require disposal, then it should probably
implement IDisposable anyway for future proofing, and callers similarly
should manage its lifetime by controlling the calling of
IDisposable.Dispose().

Most objects aren't so monolithic, though. They either deal immediately
with the external world, or they don't. One uses using() or some
ownership mechanism for the first, and lets GC take care of the others.
Somehow I feel more comfortable with C++'s way of letting the user decide
how he wants the object to be managed (automatically on the stack
or manually with new/free).

Sure. I only wished to point out that in many ways it isn't a real
distinction, because it's normally obvious which objects need disposal
and which don't.

-- Barry
 
M

Martin Carpella

Volker Hetzer said:
Yes, that would often work, but as far as I know there's no guarantee
that the garbage collector gets called.
When you have to hand back a license token this is not nice.

As long as the AppDomain is shut down properly, finalizers will get
called but with a timeout. So yes, there is no guarantee they really get
called.

But even if you have C++-like stack semantics destructors will not necessarily
get called, e.g. if the process is canceled externally, power failures,
etc.

C++/CLI gets very close to the stack semantics of C++, well, the memory
is not released on exit of the variable's scope, but at least Dispose()
is called.

Best regards,
Martin
 
V

Volker Hetzer

C++/CLI gets very close to the stack semantics of C++, well, the memory
is not released on exit of the variable's scope, but at least Dispose()
is called.
I think I'll have a look at this. If the programming overhead relative
to C# is manageable, maybe I'll use this instead.

Thanks a lot for your help!
Volker
 

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

Top