static class inheritance, generalized

  • Thread starter Ben Voigt [C++ MVP]
  • Start date
B

Ben Voigt [C++ MVP]

I'm trying to construct a compelling example of the need for a language
feature, with full support for generics, to introduce all static members and
nested classes of another type into the current name search scope.

i.e. a very simple application would be

class ManyComputations
{
calling System.Math;

... z = Sin(3*x) + Log(y); // qualifiers not needed
}

This provides a superset of the "inherit from a static class" concept,
without actually using inheritance or conflicting with "sealed".

All C# experts are invited to join the discussion over in
microsoft.public.dotnet.languages.vc in the thread titled "howto decouple in
..NET?" Some familiarity with C++/CLI is a definite plus.

Thanks.
 
J

Jon Skeet [C# MVP]

Ben Voigt said:
I'm trying to construct a compelling example of the need for a language
feature, with full support for generics, to introduce all static members and
nested classes of another type into the current name search scope.

i.e. a very simple application would be

class ManyComputations
{
calling System.Math;

... z = Sin(3*x) + Log(y); // qualifiers not needed
}

This provides a superset of the "inherit from a static class" concept,
without actually using inheritance or conflicting with "sealed".

Because it's not actually inheritance, I'd try to avoid using the term
wherever possible.
All C# experts are invited to join the discussion over in
microsoft.public.dotnet.languages.vc in the thread titled "howto decouple in
.NET?" Some familiarity with C++/CLI is a definite plus.

I'll see if I've got time to join in.

One reason MS *might* want to do it - Java has it :)
The syntax used is quite nice, too - static import. The equivalent
would be static using:

static using System.Math;

I wouldn't suggest doing it within a class though - I'd put it with the
rest of the using statements.
 
B

Ben Voigt [C++ MVP]

Jon Skeet said:
Because it's not actually inheritance, I'd try to avoid using the term
wherever possible.


I'll see if I've got time to join in.

One reason MS *might* want to do it - Java has it :)
The syntax used is quite nice, too - static import. The equivalent
would be static using:

static using System.Math;

I wouldn't suggest doing it within a class though - I'd put it with the
rest of the using statements.

Oh, it has to be available in a class. Absolutely positively. But I've
already explained why in the other group. That's not to say it wouldn't be
nice if it also worked at namespace scope.
 
J

Jon Skeet [C# MVP]

Ben Voigt said:
Oh, it has to be available in a class. Absolutely positively. But I've
already explained why in the other group. That's not to say it wouldn't be
nice if it also worked at namespace scope.

It looks like we're talking about *completely* different things. The
example you gave of being able to use the Sin and Log methods without
further qualification are very different from the desires you have in
expressed in the VC group, as far as I understand them (which isn't
terribly far).

For the purposes of making static members from one type available in
another type without qualification, adding the capability to using
statements is fine.

I'm not *entirely* sure what you're asking for in the VC group, but it
seems to extend *way* past that.

I think it would be a much more fruitful discussion here than in the
C++ group - and more on-topic too, if you're suggesting a C# feature
rather than a C++ feature.
 
C

Chris Mullins [MVP]

Jon Skeet said:
Ben Voigt [C++ MVP] <[email protected]> wrote:
For the purposes of making static members from one type available in
another type without qualification, adding the capability to using
statements is fine.

As I pointed out in the C++ thread, C# 3.0 does have this exact feature -
they're called Extension Methods.

http://blogs.msdn.com/abhinaba/archive/2005/09/15/467926.aspx
http://msdn2.microsoft.com/en-us/library/ms364047(vs.80).aspx#cs3spec_topic3
 
J

Jon Skeet [C# MVP]

Chris Mullins said:
As I pointed out in the C++ thread, C# 3.0 does have this exact feature -
they're called Extension Methods.

http://blogs.msdn.com/abhinaba/archive/2005/09/15/467926.aspx
http://msdn2.microsoft.com/en-us/library/ms364047(vs.80).aspx#cs3spec_topic3

It's not that *exact* feature. For one thing, it doesn't apply to
existing methods. For another, it makes them appear to be instance
methods. I certainly wouldn't want to call x.Sin() + y.Cos() in my code
- I'd much rather be able to use Cos(x) + Sin(y).

It may well go part of the way though, in many cases.
 
B

Ben Voigt [C++ MVP]

Chris Mullins said:
Jon Skeet said:
Ben Voigt [C++ MVP] <[email protected]> wrote:
For the purposes of making static members from one type available in
another type without qualification, adding the capability to using
statements is fine.

As I pointed out in the C++ thread, C# 3.0 does have this exact feature -
they're called Extension Methods.

Your post in the C++ thread got recalled before I could look at it. I was
looking forward to hearing your input, too.
 
C

Chris Mullins [MVP]

Ben Voigt said:
Your post in the C++ thread got recalled before I could look at it. I was
looking forward to hearing your input, too.

My post got recalled? How... unexpected. I wonder how that happened.

I can see it in Google Groups, for what it's worth...
 
C

Christof Nordiek

Jon Skeet said:
The equivalent
would be static using:

static using System.Math;
Hi Jon,

why the keyword static here, why not simply:

using System.Math;

Christof
 
J

Jon Skeet [C# MVP]

why the keyword static here, why not simply:

using System.Math;

I suppose that would be okay in C# (in Java you can individually
import classes, not just packages). However, given that it's not doing
*quite* the same thing as normal using directive, I think I'd prefer
the extra "static" to make it more obvious to the reader. If you're
dealing with some unfamiliar libraries, it may not be immediately
clear whether a particular name is a namespace or a class.

Jon
 
F

Frans Bouma [C# MVP]

Ben said:
I'm trying to construct a compelling example of the need for a
language feature, with full support for generics, to introduce all
static members and nested classes of another type into the current
name search scope.

i.e. a very simple application would be

class ManyComputations
{
calling System.Math;

... z = Sin(3*x) + Log(y); // qualifiers not needed
}

This provides a superset of the "inherit from a static class"
concept, without actually using inheritance or conflicting with
"sealed".

All C# experts are invited to join the discussion over in
microsoft.public.dotnet.languages.vc in the thread titled "howto
decouple in .NET?" Some familiarity with C++/CLI is a definite plus.

I agree with Jon, THIS is the C# newsgroup and C# discussions should
be held here. We already have a truckload of offtopic (i.e. which are
more about .NET than C#) discussions here so more ONtopic discussion
here would be great ;)

What you're suggesting is IMHO running into problems very quickly.
With 'Sin' and 'Cos' you might not have duplicates in scope, but what
if you have?

Furthermore, the necessity which makes you want what you're suggesting
is the friction between procedural programming and OO programming: math
methods and calculation methods are typical procedural
methods/routines, which don't really fit into the OO paradigm, unless
you'd add Sin() as a method of an int or double for example.

As the language and framework (C#, .NET) are OO, the routines have to
be placed inside a class. To refer to the methods you now have to
specify in which class they're in. This can be a bit odd at first,
because you just want to call a routine like we all did in C or Pascal
and in these languages you also didn't have to specify in which file
the routine was in, it was just there as long as you'd #include the
header file.

However, if you would go the route of 'if I have included / imported a
header/namespace with solely routines and no classes, I should be able
to call them without specifying their location', you effectively
breaking down the OO nature of C# and will introduce what C++ also has:
a way to program C-style code, without classes.

Personally I think every static method has to be specified with the
class it's in. This is for clarity which method is called (so the
reader of the code can easily understand which method is called, a big
helper in getting bug rates down) and also to avoid duplicate names.

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#)
------------------------------------------------------------------------
 
C

Christof Nordiek

Frans Bouma said:
What you're suggesting is IMHO running into problems very quickly.
With 'Sin' and 'Cos' you might not have duplicates in scope, but what
if you have?

This wouldn't be a new problem to C#. Even now using directives can import
duplicate names, in wich cases you have to use the full quailified name to
make a distinction. Or you can use using alias directives to explicitly give
different names to them.

The rules of resolving simple names would remain the same or could easily
extended.

Christof
 
J

Jon Skeet [C# MVP]

On Jun 6, 9:21 am, "Frans Bouma [C# MVP]"

What you're suggesting is IMHO running into problems very quickly.
With 'Sin' and 'Cos' you might not have duplicates in scope, but what
if you have?

Then you generate a compile-time error saying that you've got to
disambiguate.
Furthermore, the necessity which makes you want what you're
suggesting is the friction between procedural programming and OO
programming: math methods and calculation methods are typical
procedural methods/routines, which don't really fit into the OO paradigm,
unless you'd add Sin() as a method of an int or double for example.

So what do you suggest to make life nicer for those who are doing a
*lot* of trigonometry etc in code?

When used sparingly, it can really improve things IMO. Yes, it goes
against the OO nature of C#, but not everything is cleanly expressed
in OO terms.

Jon
 
C

Christof Nordiek

Frans Bouma said:
Furthermore, the necessity which makes you want what you're suggesting
is the friction between procedural programming and OO programming: math
methods and calculation methods are typical procedural
methods/routines, which don't really fit into the OO paradigm, unless
you'd add Sin() as a method of an int or double for example.

I'm not sure, what you want to say by this. Do you mean OO-languages
shouldn't have static methods at all?

BTW What you suggest would reduce the use of the method. I would have to
explicitly cast an int to double to call the sinus of it, or there had to be
a special version of Sin() in the int class, wich internally would only cast
int to double and call Sin(double).

Christof
 
B

Ben Voigt [C++ MVP]

However, if you would go the route of 'if I have included / imported a
header/namespace with solely routines and no classes, I should be able
to call them without specifying their location', you effectively
breaking down the OO nature of C# and will introduce what C++ also has:
a way to program C-style code, without classes.

I call shenanigans on your statement that this is anti-OOP. Consider:

public interface IDataLayer
{
DataSet GetProducts();
...
}

public partial class BusinessLayer <DataLayer>
where DataLayer : IDataLayer
{
}

public partial class BusinessLayer <DataLayer>
{
public class DiscountRules
{
...
}
}

public partial class BusinessLayer <DataLayer>
{
public class Reporting
{
...
}
}

public partial class ShoppingCartUI<DataLayer, LookAndFeel>
where DataLayer : IDataLayer
where LookAndFeel : IPageFormatter
{
static using BusinessLayer<DataLayer>;

public class NavigationMenu
{
delegate void NavButtonHandler(UIManager sender, NavigateEventArgs e);

event NavButtonHandler NavigateViewCart;
event NavButtonHandler NavigateAccountManagement;
event NavButtonHandler NavigateSystemManagement;

// use DiscountRules and Reporting without further qualification
}

public class UIManager
{
public DataLayer GetDataLayer() { ... }

NavigationMenu NavMenu;
}
}

public class LocalDataLayer : IDataLayer
{
// GetProducts()
...

void BackupNow();
void ReplayLogs();
void Vaccuum();
}

public class LocalAdminUI
{
static using BusinessLayer<LocalDataLayer>; // needs reporting logic
static using ShoppingCartUI<LocalDataLayer>;

static void ShowAuthenticationScreen(UIManager sender, NavigateEventArgs
e) { ... }
}

public class Configuration
{
static using BusinessLayer<LocalDataLayer>;
static using ShoppingCartUI<LocalDataLayer>;

void main()
{
UIManager uim = new UIManager();
uim.NavMenu.NavigateSystemManagement +=
LocalAdminUI.ShowAuthenticationScreen;
}
}

Now, although ShoppingCartUI and BusinessLayer don't need to know
implementation details about the data layer,
ShoppingCartUI<>.UIManager.GetDataLayer() passes a strongly-typed
LocalDataLayer which the LocalAdminUI can use to trigger a database backup,
vaccuum, etc. ShoppingCartUI and BusinessLayer would be just as happy with
a ClusteredDataLayer or WebServicesDataLayer, etc.

Ok, this isn't the best example, because the DataLayer is probably a
singleton with a long lifetime and you could just keep a reference to it in
the LocalAdminUI. But what about more classes. Consider the case where an
error event is raised because a database query failed. The handler for that
may need to go well beyond the public interface of the request in order to
perform error analysis, yet getting an adapter class created and subscribed
to the error event for each and every request created isn't necessarily
feasible. Ok you say, just do a runtime cast to get the more detailed
interface. Bad idea. You've lost compile-time static checking -- in the
error handling path, where runtime errors are likely to go unnoticed for the
longest time. Change to a different request class, and the error handler
still happily passes the unit tests against the old mock object, but now
causes a disaster at runtime at the worst possible time -- when you already
had an error you desperately need information about.

And for my system, which has nothing to do with products or shopping carts
or RDBMS, there are quite a few detectable concerns which need to be kept
loosely coupled but all work on the same object tree. A language feature to
import non-instance members into the name search space would be a huge help.
 
F

Frans Bouma [C# MVP]

Christof said:
I'm not sure, what you want to say by this. Do you mean OO-languages
shouldn't have static methods at all?

They can come in handy, but static methods are sort of a hack as well
when it comes to pure OO in a language: they give you a way to specify
procedural code in an OO language without having to instantiate an
object to call a method.

A typical example is a very simple set of routines, namely Add(int,
int) and Substract(int, int). These routines take 2 numbers and work
their logic on them.

You could argue that they should be placed in a 'Calculator' class
however, the methods itself don't work on the calculator's data, the
calculator class is actually a container to be able to compile the 2
routines, because Add and Substract are actually just routines which
work on the input and produce a single value as output.

Now, one could bicker over whether this example is a good one or not,
but that's besides the point. The point I'm trying to make is that
there is a friction between OO and procedural: you can't always express
everything in classes the way you WANT TO: sometimes procedural code is
just more convenient. However, to ALLOW that, you effectively have to
open up the language to allow 'modules' with routines which don't
belong to any class, they're just forming a library of routines you can
call.

In C#, this 'Module' idea is implemented as a class with static
methods. The suggestion now is to drop the static class and simply
allow a module with routines as that's what the end result will look
like.

I find the class with static methods not pretty, but it has an
advantage over a bucket with routines forming a library: the class name
gives the reader hints where the method is implemented:
Calculator.Add() might be hurting for the eye when it comes to true OO,
however it's IMHO better than having 'Add()' alone, and the reader then
has to GUESS in which module Add is implemented.
BTW What you suggest would reduce the use of the method. I would have
to explicitly cast an int to double to call the sinus of it, or there
had to be a special version of Sin() in the int class, wich
internally would only cast int to double and call Sin(double).

Though, ask yourself this: why do we place in one situation the method
working on a class' data IN the class the data is contained in and in
another situation we want to place the method OUTSIDE the class the
data is contained in? 10.Cos() might look weird, I agree, but
logically, it is something in line with "foo123".Substring(2);

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#)
------------------------------------------------------------------------
 
F

Frans Bouma [C# MVP]

Ben said:
I call shenanigans on your statement that this is anti-OOP. Consider:

Listen, Ben. If you want a discussion about this, you shouldn't pull
things like this. I've better things to do than join a mud fest in some
random newsgroup. I just gave an honest opinion which is also shared
among a lot of C++ developers: a lot of C++ developers want the C-style
coding constructs out of C++. There are also a lot of C++ developers
who think the opposite. All fine, but don't call my argumentation cheap
tricks, because then I'm definitely done here, OK?

A set of routines which are solely procedural (i.e. you can copy /
paste them into a C program and it works (minor syntax crap ignored),
isn't what OO is all about so if you WANT THAT in an OO program, the
language has to have a construct for that. C# has static methods for
that. It's not great, IMHO, but it gives the oppertunity to add
procedural routines which don't work on a class' internal members to a
C# program.

[snip]
Ok, this isn't the best example, because the DataLayer is probably a
singleton with a long lifetime and you could just keep a reference to
it in the LocalAdminUI. But what about more classes. Consider the
case where an error event is raised because a database query failed.
The handler for that may need to go well beyond the public interface
of the request in order to perform error analysis, yet getting an
adapter class created and subscribed to the error event for each and
every request created isn't necessarily feasible. Ok you say, just
do a runtime cast to get the more detailed interface. Bad idea.
You've lost compile-time static checking -- in the error handling
path, where runtime errors are likely to go unnoticed for the longest
time. Change to a different request class, and the error handler
still happily passes the unit tests against the old mock object, but
now causes a disaster at runtime at the worst possible time -- when
you already had an error you desperately need information about.

I'm not an expert on your system so I see not a real relevance to the
point you're trying to make.
And for my system, which has nothing to do with products or shopping
carts or RDBMS, there are quite a few detectable concerns which need
to be kept loosely coupled but all work on the same object tree. A
language feature to import non-instance members into the name search
space would be a huge help.

Though why not specify the class in which the method is defined in
front of the method? Math.Cos() instead of Cos() ?

I don't see the relevance of leaving out 'Math' here. And no, I've
never had the need for calling a static method somewhere but at the
point I'd like to call the static method I didn't know which one.

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#)
------------------------------------------------------------------------
 
F

Frans Bouma [C# MVP]

Jon said:
On Jun 6, 9:21 am, "Frans Bouma [C# MVP]"

What you're suggesting is IMHO running into problems very
quickly. With 'Sin' and 'Cos' you might not have duplicates in
scope, but what if you have?

Then you generate a compile-time error saying that you've got to
disambiguate.

When I'm reading code, all I can HOPE for is that I understand that
'Cos' is in 'Math'. It's about clarity.
So what do you suggest to make life nicer for those who are doing a
*lot* of trigonometry etc in code?

I was making a hypothetical example that it is (to me at least) rather
odd that some methods are in classes they work on, and others are in
separate classes. We all do that, putting procedural methods together
in static classes and make the methods static, simply because the
methods have no real type they work on, they're procedural.
When used sparingly, it can really improve things IMO. Yes, it goes
against the OO nature of C#, but not everything is cleanly expressed
in OO terms.

I agree OO has limits in expressiveness, especially when you need
procedural expressiveness. However EVERY degration in readability of
code, i.e. any degration of clarity, is IMHO the worse thing that can
happen to a language. that's also why I find things like 'yield' and
also delegates to some extend language constructs which should be used
with care and only there when you can't do something else. they break
down clarity of the code: "Ok, this calls a delegate, where does the
code end up now?" These kind of things should be clear, at least as
clear as possible: when a programmer doesn't understand the code s/he
reads in full without errors, s/he can't write 100% bugfree code.

Simply importing methods and calling them as if they're methods of the
class they're called in, is decreasing the clarity of the code, IMHO
and also makes it possible to program procedural applications. I know
that at times we all just want to have a main routine with some code
and that's it, but one then should pick another language.

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#)
------------------------------------------------------------------------
 
J

Jon Skeet [C# MVP]

On Jun 7, 9:14 am, "Frans Bouma [C# MVP]"

10.Cos() might look weird, I agree, but
logically, it is something in line with "foo123".Substring(2);

I was going to reply to your response to me, but this is actually the
best example I've seen. As you said elsewhere, readability is vital.
It's more important (to me) than the logic of the thing. I would far
rather read:

double dist = Sqrt (x*x+y*y);

than either of

double dist = (x*x+y*y).Sqrt();
double dist = Math.Sqrt(x*x+y*y);

and likewise I'd much rather read

double foo = Cos(theta) + Sin(alpha);

than

double foo = theta.Cos() + alpha.Sin();
double foo = Math.Cos(theta) + Math.Sin(alpha);

Do you genuinely believe that either the instance method version or
the static method version including the class name conveys the
intention of the code more simply than my preferred version?

Yes, you may occasionally want to use Intellisense to confirm which
class a method actually belongs to - although I'd say that when used
sparingly, it should always be obvious anyway. That productivity
decrease is easily matched by the improvement of readability in cases
like the above.

Could it be used stupidly? Yes. Can it also vastly improve the
readability of certain cases, particularly maths? Absolutely.

Jon
 
B

Ben Voigt [C++ MVP]

[snip]
Though why not specify the class in which the method is defined in
front of the method? Math.Cos() instead of Cos() ?

Don't you mean global::System.Math.Cos()? Or do also you see a need for not
always using the fully-qualified name?

You've missed my entire point that class members don't all fall into the
categories of (instance method/field/property/event) and (static
method/field/property/event). There are also nested classes, and these are
quite possibly a more important use of the feature than all others combined.
So even in a pure OO environment, where everything is a class, there is
still value in adding class members to the search scope.

There is a huge need for being able to omit or shorten the name of the
containing class, whether you are referring to a member field, event,
property, method, or class. Specifically, when the parent class name is
quite long, which is quite common in the presence of generics. And, the
existing "using" (alias) directive cannot be used inside a class, so it
doesn't fully support generics.

Here is a really quick example of the shortcomings of the existing "using"
directive:

Non-generic:

class LinkedListNode { ... }

using Node = LinkedListNode; // of dubious value, not saving much typing

class LinkedList { /* use Node here */ }

Generic:

class LinkedListNode<TValue> { ... }

using Node = LinkedListNode<TValue>; // error, not in scope of TValue

class LinkedList<TValue>
{
using Node = LinkedListNode<TValue>; // error: here TValue is available,
but the using directive isn't allowed
/* use Node here */
}
 
Top