Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > [RCR] abstract method in Ruby

Reply
Thread Tools

[RCR] abstract method in Ruby

 
 
kwatch
Guest
Posts: n/a
 
      03-11-2006
To define abstract method in Ruby, I use NotImplementedError like the
following:

----------
class Foo
def m1
raise NotImpelemntedError("#{self.class.name}#m1() is not
implemented.")
end
end
----------

I think it is convenient if the Module#abstract_method is defined.

----------
class Module
def abstract_method(*method_names)
method_names.each do |name|
s = <<-END
def #{name}
mesg = "\#{self.class.name}##{name}() is not implemented."
raise NotImplementedError.new(mesg)
end
END
module_eval s
end
end

class Foo
abstract_method :m1, :m2, :m3 # define abstract methods
end

obj = Foo.new
obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError)
----------

But this solution doesn't allow us to define a method with arguments.
The following is another solution to define abstract method
which is able to define a method with arguments.

? example.rb
----------
module Abstract # or Module?
def not_implemented # or should_be_implemented?
backtrace = caller()
method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
mesg = "#{self.class.name}##{method_name}() is not implemented."
err = NotImplementedError.new(mesg)
err.set_backtrace(backtrace)
raise err
end
end

class Foo
include Abstract
def m1(arg)
not_implemented
end
end

obj = Foo.new
p obj.m1('abc') #=> example.rb:20: Foo#m1() is not implemented.
(NotImplementedError)
----------

I think this is useful for everyone and I hope it will be included in
Ruby.
Could you give me any advices?

--
regards,
kwatch

 
Reply With Quote
 
 
 
 
kwatch
Guest
Posts: n/a
 
      03-11-2006
Thanks Austin,

Austin Ziegler wrote:
>
> In the last four years of using Ruby, I thought I needed abstract
> methods in the first few months. Then I learned what value Modules as
> mixins gave me.
>
> I do not believe that this is a common enough need that it needs to be
> in the core of Ruby.


Well, I think that abstract method is more basic than 'singleton.rb'
or 'delegate.rb' which are bundled in Ruby.


> I encourage you to do what others have done with this sort of
> mismatched feature and make a library that implements it and make it
> available for use. Your pure-Ruby implementation looks more than
> sufficient.


I'll make it library and register it to RubyForge.


> More than that, though, I encourage you to rethink why you need
> abstract methods. Most of the time this is because you're thinking in
> terms of C++ or Java inheritance, when Ruby's mixins are both more
> powerful and applicable in most cases where you would define a
> hierarchy that has abstract methods.


In my opinion, 'mixin' is one thing and 'abstract method' is another.
Mixin doesn't cover abstract method.

The following is an example of visitor pattern.
It shows that mixin doesn't cover abstract method.

----------
module Visitor
def visit_foo(acceptor) # abstract method
mesg = "#{self.class.name}#visit_foo() is not implemented."
raise NotImplementedError.new(mesg)
end

def visit_bar(acceptor) # abstract method
mesg = "#{self.class.name}#visit_foo() is not implemented."
raise NotImplementedError.new(mesg)
end
end

class MyVisitor
include Visitor # mix-in

def visit_foo(acceptor)
puts "visit_foo() called."
end

def visit_bar(acceptor)
puts "visit_bar() called."
end
end

class Foo
def accept(visitor)
visitor.visit_foo(self)
end
end

class Bar
def accept(visitor)
visitor.visit_bar(self)
end
end
----------

Ruby's mix-in is more sophisticated solution than interface of Java
or multiple inheritance of C++, I think.
But mix-in and abstract method are different thing.

--
regards,
kwatch

 
Reply With Quote
 
 
 
 
Logan Capaldo
Guest
Posts: n/a
 
      03-11-2006

On Mar 11, 2006, at 5:23 PM, kwatch wrote:

> Thanks Austin,
>
> Austin Ziegler wrote:
>>
>> In the last four years of using Ruby, I thought I needed abstract
>> methods in the first few months. Then I learned what value Modules as
>> mixins gave me.
>>
>> I do not believe that this is a common enough need that it needs
>> to be
>> in the core of Ruby.

>
> Well, I think that abstract method is more basic than 'singleton.rb'
> or 'delegate.rb' which are bundled in Ruby.
>
>
>> I encourage you to do what others have done with this sort of
>> mismatched feature and make a library that implements it and make it
>> available for use. Your pure-Ruby implementation looks more than
>> sufficient.

>
> I'll make it library and register it to RubyForge.
>
>
>> More than that, though, I encourage you to rethink why you need
>> abstract methods. Most of the time this is because you're thinking in
>> terms of C++ or Java inheritance, when Ruby's mixins are both more
>> powerful and applicable in most cases where you would define a
>> hierarchy that has abstract methods.

>
> In my opinion, 'mixin' is one thing and 'abstract method' is another.
> Mixin doesn't cover abstract method.
>
> The following is an example of visitor pattern.
> It shows that mixin doesn't cover abstract method.
>
> ----------
> module Visitor
> def visit_foo(acceptor) # abstract method
> mesg = "#{self.class.name}#visit_foo() is not implemented."
> raise NotImplementedError.new(mesg)
> end
>
> def visit_bar(acceptor) # abstract method
> mesg = "#{self.class.name}#visit_foo() is not implemented."
> raise NotImplementedError.new(mesg)
> end
> end
>
> class MyVisitor
> include Visitor # mix-in
>
> def visit_foo(acceptor)
> puts "visit_foo() called."
> end
>
> def visit_bar(acceptor)
> puts "visit_bar() called."
> end
> end
>
> class Foo
> def accept(visitor)
> visitor.visit_foo(self)
> end
> end
>
> class Bar
> def accept(visitor)
> visitor.visit_bar(self)
> end
> end
> ----------
>
> Ruby's mix-in is more sophisticated solution than interface of Java
> or multiple inheritance of C++, I think.
> But mix-in and abstract method are different thing.
>
> --
> regards,
> kwatch
>
>


I think you're over engineering. Let's consider the Enumerable module
for instance. It has an "abstract" method of sorts, each.

class A
include Enumerable
end

a = A.new
a.map { |x| x + 1 }

Oh look, this code already raises an exception, a NoMethodError. Now
I know that to include Enumerable I have to have an each method.
That's all there is to it. Look at your Visitor example for instance,
in ruby there's not even a need for the Visitor module, all you have
to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
one cares who your parents were, all they care about is if you know
what you are talking about.

class MyVisitor
def visit_foo(acceptor)
puts "visit_foo() called."
end

def visit_bar(acceptor)
puts "visit_bar() called."
end
end

class Foo
def accept(visitor)
visitor.visit_foo(self)
end
end

class Bar
def accept(visitor)
vistor.visit_bar(self)
end
end

Bam! Same thing as your code, will still raise the same exceptions,
but ONLY if you really need them. Start thinking like a duck man. Ask
yourself what is the purpose of an abstract method. Then ask yourself
if that need is already fufilled in ruby.



 
Reply With Quote
 
Jacob Fugal
Guest
Posts: n/a
 
      03-11-2006
On 3/11/06, kwatch <(E-Mail Removed)> wrote:
> I think it is convenient if the Module#abstract_method is defined.


I'm of a similar opinion with others that predeclaring an abstract
method that raises NotImplementedError is of limited use when compared
with the existing NoMethodError duck-typing approach. As such, I don't
think it belongs in the core.

*However*, this is a useful concept which could be used to extend the
capabilities of the language for those who do still want it. I
encourage you to build a library from this idea and publicize it. Just
because it doesn't belong in the core doesn't mean it won't be useful
to some. One place I can see this being used is if the
NotImplementedError gave a more descriptive output, such as "#{self}
requires that the host implement the method '#{method_name}'." E.g.
"Enumerable requires that the host implement the method 'each'."

> ----------
> class Module
> def abstract_method(*method_names)
> method_names.each do |name|
> s =3D <<-END
> def #{name}
> mesg =3D "\#{self.class.name}##{name}() is not implemented."
> raise NotImplementedError.new(mesg)
> end
> END
> module_eval s
> end
> end
>
> class Foo
> abstract_method :m1, :m2, :m3 # define abstract methods
> end
>
> obj =3D Foo.new
> obj.m1 #=3D> Foo#m1() is not implemented yet. (NotImplementedError)
> ----------
>
> But this solution doesn't allow us to define a method with arguments.


One thing that you can do to make this approach (which seems cleaner
and simpler than the backtrace manipulation approach you later
proposed) more flexible by removing the arity restriction on the
method using the splat operator:

$ cat abstract.rb
class Module
def abstract_method(*method_names)
mesg_template =3D "#{self} requires that the host implement the
method '%s'."
method_names.each do |name|
mesg =3D mesg_template % [name]
module_eval <<-END
def #{name}(*args)
raise NotImplementedError.new("#{mesg}")
end
END
end
end
end

module MyModule
def foo
bar("test")
end

abstract_method :bar
end

class MyClass
include MyModule
end

a =3D MyClass.new
b =3D MyClass.new

class << a
def bar( s )
puts s
end
end

a.foo
b.foo

$ ruby abstract.rb
test
(eval):2:in `bar': MyModule requires that the host implement the
method 'bar'. (NotImplementedError)
from abstract.rb:17:in `foo'
from abstract.rb:37

--
Jacob Fugal


 
Reply With Quote
 
kwatch
Guest
Posts: n/a
 
      03-12-2006
Logan,

> Oh look, this code already raises an exception, a NoMethodError. Now
> I know that to include Enumerable I have to have an each method.
> That's all there is to it.


I think it is very important that the code itself is descriptive.
The following code doesn't describe that method each() is abstract.

module Enumerable
def map
arr = []
each { |elem| arr << yield(elem) }
arr
end
end

The following code itself describes that method each() is abstract.
It's more descriptive.

module Enumerable
abstract_method :each
def map
arr = []
each { |elem| arr << yield(elem) }
arr
end
end

Please take care of reading code, as well as writing code.
You may insist that documentation is sufficient to describe that,
but documentation is assistant and code should be prime.


> Oh look, this code already raises an exception, a NoMethodError.


NoMethodError is not proper to abstract method, I think.


> Look at your Visitor example for instance,
> in ruby there's not even a need for the Visitor module, all you have
> to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
> one cares who your parents were, all they care about is if you know
> what you are talking about.


Assume that you need to define many visitor classes.

module Visitor
abstract_method :visit_foo, :visit_bar
end

class Hoge
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

class Fuga
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

class Geji
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

The above code itself describes that "class Hoge, Fuga, and Geji
are visotr classes" very clearly.
'Visitor' module may not be necessary when a number of visitor class
is only 1.
But there should be 'Visitor' module in the case that many visitor
classes are needed. It's more descriptive.


> Start thinking like a duck man.


You mean 'duck typing'?
Duck typing is one thing and abstract method is another.


> Ask yourself what is the purpose of an abstract method.
> Then ask yourself if that need is already fufilled in ruby.


Abstract method is useful to realize 'descriptive code'.
It increases code maintanancability.


--
regards,
kwatch


Logan Capaldo wrote:

> On Mar 11, 2006, at 5:23 PM, kwatch wrote:
>
> > Thanks Austin,
> >
> > Austin Ziegler wrote:
> >>
> >> In the last four years of using Ruby, I thought I needed abstract
> >> methods in the first few months. Then I learned what value Modules as
> >> mixins gave me.
> >>
> >> I do not believe that this is a common enough need that it needs
> >> to be
> >> in the core of Ruby.

> >
> > Well, I think that abstract method is more basic than 'singleton.rb'
> > or 'delegate.rb' which are bundled in Ruby.
> >
> >
> >> I encourage you to do what others have done with this sort of
> >> mismatched feature and make a library that implements it and make it
> >> available for use. Your pure-Ruby implementation looks more than
> >> sufficient.

> >
> > I'll make it library and register it to RubyForge.
> >
> >
> >> More than that, though, I encourage you to rethink why you need
> >> abstract methods. Most of the time this is because you're thinking in
> >> terms of C++ or Java inheritance, when Ruby's mixins are both more
> >> powerful and applicable in most cases where you would define a
> >> hierarchy that has abstract methods.

> >
> > In my opinion, 'mixin' is one thing and 'abstract method' is another.
> > Mixin doesn't cover abstract method.
> >
> > The following is an example of visitor pattern.
> > It shows that mixin doesn't cover abstract method.
> >
> > ----------
> > module Visitor
> > def visit_foo(acceptor) # abstract method
> > mesg = "#{self.class.name}#visit_foo() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> >
> > def visit_bar(acceptor) # abstract method
> > mesg = "#{self.class.name}#visit_foo() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> > end
> >
> > class MyVisitor
> > include Visitor # mix-in
> >
> > def visit_foo(acceptor)
> > puts "visit_foo() called."
> > end
> >
> > def visit_bar(acceptor)
> > puts "visit_bar() called."
> > end
> > end
> >
> > class Foo
> > def accept(visitor)
> > visitor.visit_foo(self)
> > end
> > end
> >
> > class Bar
> > def accept(visitor)
> > visitor.visit_bar(self)
> > end
> > end
> > ----------
> >
> > Ruby's mix-in is more sophisticated solution than interface of Java
> > or multiple inheritance of C++, I think.
> > But mix-in and abstract method are different thing.
> >
> > --
> > regards,
> > kwatch
> >
> >

>
> I think you're over engineering. Let's consider the Enumerable module
> for instance. It has an "abstract" method of sorts, each.
>
> class A
> include Enumerable
> end
>
> a = A.new
> a.map { |x| x + 1 }
>
> Oh look, this code already raises an exception, a NoMethodError. Now
> I know that to include Enumerable I have to have an each method.
> That's all there is to it. Look at your Visitor example for instance,
> in ruby there's not even a need for the Visitor module, all you have
> to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
> one cares who your parents were, all they care about is if you know
> what you are talking about.
>
> class MyVisitor
> def visit_foo(acceptor)
> puts "visit_foo() called."
> end
>
> def visit_bar(acceptor)
> puts "visit_bar() called."
> end
> end
>
> class Foo
> def accept(visitor)
> visitor.visit_foo(self)
> end
> end
>
> class Bar
> def accept(visitor)
> vistor.visit_bar(self)
> end
> end
>
> Bam! Same thing as your code, will still raise the same exceptions,
> but ONLY if you really need them. Start thinking like a duck man. Ask
> yourself what is the purpose of an abstract method. Then ask yourself
> if that need is already fufilled in ruby.


 
Reply With Quote
 
kwatch
Guest
Posts: n/a
 
      03-12-2006
Jacob Fugal wrote:
>
> I'm of a similar opinion with others that predeclaring an abstract
> method that raises NotImplementedError is of limited use when compared
> with the existing NoMethodError duck-typing approach. As such, I don't
> think it belongs in the core.


Hmm...
IMO, abstract method is more useful than 'singleton.rb' or
'delegate.rb'.
It's just my opinion.


> *However*, this is a useful concept which could be used to extend the
> capabilities of the language for those who do still want it. I
> encourage you to build a library from this idea and publicize it. Just
> because it doesn't belong in the core doesn't mean it won't be useful
> to some.


Yes, I'm going to release 'abstract.rb'.


> One place I can see this being used is if the
> NotImplementedError gave a more descriptive output, such as "#{self}
> requires that the host implement the method '#{method_name}'." E.g.
> "Enumerable requires that the host implement the method 'each'."

....(snip)...
> One thing that you can do to make this approach (which seems cleaner
> and simpler than the backtrace manipulation approach you later
> proposed) more flexible by removing the arity restriction on the
> method using the splat operator:


Thaks for your good advice.
I changed Module#abstract_method() like the following:

----------
class Module
def abstract_method args_str, *method_names
method_names.each do |name|
mesg = "class %s should implement abstract method
`#{self.name}##{name}()'."
module_eval <<-END
def #{name}(#{args_str})
err = NotImplementedError.new(mesg % self.class.name)
err.set_backtrace caller()
raise err
end
END
end
end
end
----------

Manipulating backtrace of exception is need in order to show
linenumber in which an abstract method is invoked.

example:

----------
require 'abstract'
class Foo
abstract_method '*args', :m1, :m2 # removing the arity
restriction
end
class Bar < Foo
def m1; puts "Foo#m1() called."; end
end
obj = Bar.new
obj.m1 #=> "Foo#m1() called."
obj.m2 #=> ex.rb:10: class Bar should implement abstract method
`Foo#m2()'. (NotImplementedError)
----------


--
regards,
kwatch


Jacob Fugal wrote:

> On 3/11/06, kwatch <(E-Mail Removed)> wrote:
> > I think it is convenient if the Module#abstract_method is defined.

>
> I'm of a similar opinion with others that predeclaring an abstract
> method that raises NotImplementedError is of limited use when compared
> with the existing NoMethodError duck-typing approach. As such, I don't
> think it belongs in the core.
>
> *However*, this is a useful concept which could be used to extend the
> capabilities of the language for those who do still want it. I
> encourage you to build a library from this idea and publicize it. Just
> because it doesn't belong in the core doesn't mean it won't be useful
> to some. One place I can see this being used is if the
> NotImplementedError gave a more descriptive output, such as "#{self}
> requires that the host implement the method '#{method_name}'." E.g.
> "Enumerable requires that the host implement the method 'each'."
>
> > ----------
> > class Module
> > def abstract_method(*method_names)
> > method_names.each do |name|
> > s = <<-END
> > def #{name}
> > mesg = "\#{self.class.name}##{name}() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> > END
> > module_eval s
> > end
> > end
> >
> > class Foo
> > abstract_method :m1, :m2, :m3 # define abstract methods
> > end
> >
> > obj = Foo.new
> > obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError)
> > ----------
> >
> > But this solution doesn't allow us to define a method with arguments.

>
> One thing that you can do to make this approach (which seems cleaner
> and simpler than the backtrace manipulation approach you later
> proposed) more flexible by removing the arity restriction on the
> method using the splat operator:
>
> $ cat abstract.rb
> class Module
> def abstract_method(*method_names)
> mesg_template = "#{self} requires that the host implement the
> method '%s'."
> method_names.each do |name|
> mesg = mesg_template % [name]
> module_eval <<-END
> def #{name}(*args)
> raise NotImplementedError.new("#{mesg}")
> end
> END
> end
> end
> end
>
> module MyModule
> def foo
> bar("test")
> end
>
> abstract_method :bar
> end
>
> class MyClass
> include MyModule
> end
>
> a = MyClass.new
> b = MyClass.new
>
> class << a
> def bar( s )
> puts s
> end
> end
>
> a.foo
> b.foo
>
> $ ruby abstract.rb
> test
> (eval):2:in `bar': MyModule requires that the host implement the
> method 'bar'. (NotImplementedError)
> from abstract.rb:17:in `foo'
> from abstract.rb:37
>
> --
> Jacob Fugal


 
Reply With Quote
 
Meinrad Recheis
Guest
Posts: n/a
 
      03-12-2006
------=_Part_6075_13950129.1142151951941
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On 3/12/06, kwatch <(E-Mail Removed)> wrote:
[...]

> Duck typing is one thing and abstract method is another.
>
>

hi kwatch,
if you want serious discussion then it would be great if you were able to
tell us why you think so.
a statement (alone) is nothing worth if it is not supported by reasonable
arguments.

-- henon

------=_Part_6075_13950129.1142151951941--


 
Reply With Quote
 
Logan Capaldo
Guest
Posts: n/a
 
      03-12-2006
--Apple-Mail-1-661157955
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
delsp=yes;
format=flowed


On Mar 12, 2006, at 2:38 AM, kwatch wrote:

> I think it is very important that the code itself is descriptive.
> The following code doesn't describe that method each() is abstract.


I think then we have a difference of opinion of the meaning and usage
of abstract methods.
I am of the opinion that they exist to enforce stronger typing,
especially at compile time. It's a solution to the problem of having
a class we're the implementation of a given method is given to a
child class but all methods available to a class must be known at
compile time. It's especially helpful when the abstract method must
return something, and there is no sane default.

class A {
int someAbstractMethod( ) {
// If I don't have abstract methods, what should I return?
// whatever I return, it won't be correct and it won't
force child classes
// to implement me
}
}


OTOH in ruby since it's dynamically typed, the compiler won't
complain about undefined methods until they actually get called (if
they are still undefined)

eg
class A {
someOtherMethod( ) {
x = someAbstractMethod( ); // forces child classes to
implement it simply by calling it
}
}

Now if you want to have an argument about static vs. dynamic typing
that's one thing. You say that it's important that code be
descriptive. You also say that documentation is insufficient. I
disagree, and say no code is possibly descriptive enough. Whether
attempting to call a method
that relies on an "abstract" method raises a NoMethodError or a
NotImplementedError the result is the same. The programmer must go
read the documentation (or possibly the calling code) to figure out
what was expected of him.

Basically, I feel abstract methods are a primarily feature of static
typing and help ensure the correctness of your code. But they are a
typing feature and the error message you get from them isn't any more
descriptive than "function max expected int, got string"

Tangentially related to this, I find your Visitor example a little
weak, since your Visitor module provides no methods of its own.
Modules are not Java interfaces, and the only reason to write
"include Visitor" in your code is to say
# this class implements the methods required to visit other objects
I think you've turned the idea of descriptive code into a degenerate
case of ALL this code does is describe. It has no functional purpose.
It's like using no-ops to spell out documentation in morse-code
(admittedly, that analogy is a bit ridiculous).

Feel free to ignore the previous paragraph by saying something along
the lines of "Well of course a real visitor module would have
additional methods, it was just an example."
--Apple-Mail-1-661157955--


 
Reply With Quote
 
Erik Veenstra
Guest
Posts: n/a
 
      03-12-2006
> To define abstract method in Ruby, I use NotImplementedError
> like the following:


You can't call them *abstract* methods if you implement them
like this.

In Java, the presence of methods is checked at compiletime, if
they are defined "abstract". Your solution only checks the
presence of these methods at runtime, which is already checked
by Ruby itself.

So, what functionality or checks are you really adding?

gegroet,
Erik V. - http://www.erikveen.dds.nl/

 
Reply With Quote
 
Benjohn Barnes
Guest
Posts: n/a
 
      03-12-2006

On 12 Mar 2006, at 20:48, Austin Ziegler wrote:
*snip*
> What you've got is no better than:
>
> # Every method provided in Enumerable requires that the including
> # class defines an #each method that iterates one item at a time.
> module Enumerable
> def map
> arr = []
> each { |elem| arr << yield(elem) }
> arr
> end
> end
>
> Except that it actually adds a little code for what is essentially a
> documentation annotation. As I said, it adds little to no value to
> Ruby
> and IMO doesn't belong in the core.


I still think that kwatch was on to something. It does do more than
merely document that the method should be implemented. It describes
intention, and provides a uniform and programatic means of doing so.
As well as filling in the default function, it could perhaps be used
to fill in rdoc generated documentation such that you get a warning
about all methods that implementations must provide. Rather than
every class that has abstract methods needing to write that
documentation and maintain it, it needs to be done once. It's DRYer.
I'm sure there are other uses it could be put to, such as interfacing
with a static checker if you wanted to build one.

I'm not saying that I'd necessarily use it either, but I think the
idea has merit. It sounds like he's not been put off anyway. If it
turns out to be useful over a period of use, and is adopted by some
other users, then that's all good and splendid. It's good that people
are playing with different ideas that could be useful - it saves me
needing to.




 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Using "abstract" on a class with no abstract method Stefan Ram Java 27 08-17-2009 12:36 AM
Abstract method in non-abstract class Chris Zopers ASP .Net 2 08-08-2008 11:40 AM
About abstract class and abstract method Sameer Java 4 08-31-2005 12:59 AM
Deriving abstract class from non-abstract class Matthias Kaeppler Java 1 05-22-2005 01:28 PM
Abstract Classes w/o abstract methods DaKoadMunky Java 4 04-20-2004 04:53 AM



Advertisments