Inner classes: Difference between revisions

Added FreeBASIC
(Added Algol 68)
(Added FreeBASIC)
 
(11 intermediate revisions by 6 users not shown)
Line 2:
 
;Definition
In [[wp:Object-oriented_programming|object-oriented programming]], an '''inner''' or '''nested class''' class is a class declared entirely within the body of another class or interface.
 
It is not the same as a '''subclass''' which is a class which inherits members from another class or classes and can be declared anywhere the parent class(es) are within scope. However, inner classes may nevertheless be subclasses of other classes as well.
Line 11:
Illustrate your answer by creating an inner class with a constructor, an instance method and field and show how to instantiate it.
 
If youyour language does not support the object oriented paradigm, you may either omit this task or describe (and substitute in your example) any equivalent structure(s) which the language does have.
 
;Reference
Line 50:
PROC new outer = REF REF OUTER:
BEGIN
HEAP OUTER thisv := OUTER( 0, new outer, NIL, print outer );
, new outer
, NIL
, ( REF OUTER this )VOID:
print( ( "[", whole( omember OF this, 0 ), "]" ) )
);
HEAP REF OUTER this := thisv;
oinner OF this := new inner( this );
Line 57 ⟶ 62:
PROC new inner = ( REF REF OUTER super )REF REF INNER:
BEGIN
HEAP INNER thisv := INNER( super, " ", new inner, print inner );
, " "
, new inner
, ( REF INNER this )VOID:
print( ( "<<", cmember OF this
, "><", whole( omember OF super OF this, 0 )
, ">>"
)
)
);
HEAP REF INNER this := thisv;
this
END # new inner # ;
# print methods #
PROC print outer = ( REF OUTER this )VOID:
print( ( "[", whole( omember OF this, 0 ), "]" ) );
PROC print inner = ( REF INNER this )VOID:
print( ( "<<", cmember OF this
, "><", whole( omember OF super OF this, 0 )
, ">>"
)
);
 
REF OUTER o := new outer; # create an instance of OUTER #
Line 159 ⟶ 164:
vec[0] = 1
</pre>
 
=={{header|FreeBASIC}}==
{{trans|Go}}
FreeBASIC is not an object-oriented programming language and does not have support for internal classes. However, you can simulate some features of object-oriented programming using Type and Sub.
<syntaxhighlight lang="vbnet">Type Inner
campo As Integer
End Type
 
Type Outer
campo As Integer
interno As Inner
End Type
 
Sub outerMethod(o As Outer)
Print "Outer's field has a value of "; o.field
End Sub
 
Sub innerMethod(o As Outer)
Print "Inner's field has a value of "; o.interno.field
End Sub
 
Dim As Outer o
o.field = 43
o.interno.field = 42
innerMethod(o)
outerMethod(o)
 
Dim As Outer p
p.field = 45
p.interno.field = 44
innerMethod(p)
outerMethod(p)
 
Sleep</syntaxhighlight>
{{out}}
<pre>Same as Go entry.</pre>
 
=={{header|Go}}==
Go supports some aspects of OO albeit in an unorthodox manner:
 
* Structs are used rather than classes.
* Any methods are always defined outside the struct itself but within the containing package.
* Struct fields are never private to the struct itself though, unless they begin with an upper case letter, they are private to the containing package.
* Structs do not support inheritance - composition can be used instead.
* Polymorphism is supported to some extent via the use of interfaces.
 
It is possible to nest structs as the following example shows. However, the problem here is that the nested struct has an anonymous type and the only way to give it methods is via an instance of the Outer struct.
 
In practice it would probably be better to declare the nested struct independently but within the same package and achieve encapsulation by restricting the package to just those two structs.
<syntaxhighlight lang="go">package main
 
import "fmt"
 
type Outer struct {
field int
Inner struct {
field int
}
}
 
func (o *Outer) outerMethod() {
fmt.Println("Outer's field has a value of", o.field)
}
 
func (o *Outer) innerMethod() {
fmt.Println("Inner's field has a value of", o.Inner.field)
}
 
func main() {
o := &Outer{field: 43}
o.Inner.field = 42
o.innerMethod()
o.outerMethod()
/* alternative but verbose way of instantiating */
p := &Outer{
field: 45,
Inner: struct {
field int
}{
field: 44,
},
}
p.innerMethod()
p.outerMethod()
}</syntaxhighlight>
 
{{out}}
<pre>
Inner's field has a value of 42
Outer's field has a value of 43
Inner's field has a value of 44
Outer's field has a value of 45
</pre>
 
=={{header|J}}==
 
J allows inner classes, but because such classes are always public,
there is little or no utility to be had, nesting classes in J.
 
Class definition for task:
 
<syntaxhighlight lang=J>coclass 'baggagecheck'
 
create=: {{
data=: keys=: i.0
mysn=: '' conew 'serialnumber'
}}
 
create_serialnumber_=: {{number=: 0}}
destroy_serialnunber_=: codestroy
get_serialnumber_=: {{number=: 1+number}}
 
destroy=: {{
destroy__mysn ''
codestroy ''
}}
 
checkin=: {{
sn=.get__mysn''
data=: data,<y
keys=: keys,sn
sn
}}
 
checkout=: {{
r=.>(keys i. y){data
b=. keys~:y
data=: b#data
keys=: b#keys
r
}}</syntaxhighlight>
 
Example use:
 
<syntaxhighlight lang=J> checker=: '' conew 'baggagecheck'
checkin__checker 'suitcase'
1
checkin__checker 'box'
2
checkin__checker 'bicycle'
3
checkout__checker 2
box
</syntaxhighlight>
 
=={{header|Julia}}==
 
Julia allows inner classes, but because such classes are always public,
there is little or no utility to be had nesting classes in Julia. Private
methods in Julia are best simulated via modules which limit their exports.
 
Anything that can be done with inner classes can be accomplished in Julia just as
well with the structs not nested, and the non-nested versions may be easier to
understand. Furthermore, the new() function used for inner constructors in Julia
refers only to the outermost struct, so the inner class must have any non-implict
constructors that may be needed defined outside the struct.
<syntaxhighlight lang = "julia">
""" see the Outer class in C++ example """
struct Outer
m_privateField::Int
 
""" Inner class in example """
struct Inner
m_innerValue::Int
end
end
 
""" adds the values from the outer and inner class objects """
addouter(inner::Inner, outer::Outer) = outer.m_privateField + inner.m_innerValue
 
"""
Test the functions. Iterables in Julia are structs for which the iterate()
function is defined, so no need for inner classes for that
"""
function main()
inner = Inner(42)
outer = Outer(1)
outplusin = addouter(inner, outer)
println("sum: $outplusin")
end
 
main()
</syntaxhighlight>
 
=={{header|Phix}}==
Phix has no support whatsoever for inner classes. You can of course do something like this:
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- (classes)</span>
<span style="color: #008080;">class</span> <span style="color: #000000;">inner</span>
<span style="color: #008080;">public</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">is</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">v</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">this</span><span style="color: #0000FF;">.</span><span style="color: #000000;">v</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">class</span>
<span style="color: #008080;">class</span> <span style="color: #000000;">outer</span>
<span style="color: #008080;">public</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">v</span>
<span style="color: #008080;">public</span> <span style="color: #000000;">inner</span> <span style="color: #000000;">i</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">ois</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">inner</span> <span style="color: #000000;">ti</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">this</span><span style="color: #0000FF;">.</span><span style="color: #000000;">i</span> <span style="color: #000080;font-style:italic;">-- (a needed compiler hint)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">ti</span><span style="color: #0000FF;">.</span><span style="color: #000000;">is</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">class</span>
<span style="color: #000000;">outer</span> <span style="color: #000000;">o</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new</span><span style="color: #0000FF;">({</span><span style="color: #000000;">42</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">new</span><span style="color: #0000FF;">(</span><span style="color: #000000;">inner</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})})</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">o</span><span style="color: #0000FF;">.</span><span style="color: #000000;">v</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">o</span><span style="color: #0000FF;">.</span><span style="color: #000000;">i</span><span style="color: #0000FF;">.</span><span style="color: #000000;">v</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">o</span><span style="color: #0000FF;">.</span><span style="color: #000000;">v</span><span style="color: #0000FF;">+</span><span style="color: #000000;">o</span><span style="color: #0000FF;">.</span><span style="color: #000000;">i</span><span style="color: #0000FF;">.</span><span style="color: #000000;">v</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">o</span><span style="color: #0000FF;">.</span><span style="color: #000000;">ois</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
A shown, Phix often needs explicit compiler hints when dealing with classes, without "ti" above it treats "this.i" as still somehow being an "outer", and admittedly there is no real access to outer's contents within inner. Instead you would need shims like that ois() to explicitly pass along everything it needs.<br>
It is also possible to pass routines around directly, such as i.is and o.ois [ie no parenthesis] and then invoke them with an explicit "this", which can get round some of those limitations, and act as an alternative to those compiler hints.
{{out}}
<pre>
42
1
43
43
</pre>
 
=={{header|Raku}}==
Raku supports nested classes, however they are really only useful for grouping units of behavior together into a namespace. There is no particular benefit as far as access to private methods or attributes that can't be achieved by non-nested classes. Access to inner classes must use fully qualified paths.
 
<syntaxhighlight lang="raku" line>class Outer {
has $.value is rw;
method double { self.value ×= 2 }
 
class Inner {
has $.value is rw;
}
}
 
# New Outer instance with a value of 42.
my $outer = Outer.new(:value(42));
 
say .^name, ' ', .value given $outer;
$outer.double;
say .^name, ' ', .value given $outer;
 
# New Inner instance with no value set. Note need to specify fully qualified name.
my $inner = Outer::Inner.new;
 
# Set a value after the fact.
$inner.value = 16;
 
# There is no way for the Inner object to call the Outer .double method.
# It is a separate, distinct class, just in a funny namespace.
say .^name, ' ', .value given $inner;
$inner.value /=2;
say .^name, ' ', .value given $inner;</syntaxhighlight>
{{out}}
<pre>Outer 42
Outer 84
Outer::Inner 16
Outer::Inner 8</pre>
 
=={{header|Wren}}==
Line 165 ⟶ 425:
However, it is possible to declare a class within either a method or function and we can use this feature to simulate an inner class.
 
To make things a little more interesting the inner class in the following example also inherits from the outer class. In fact inheritance is the only way for the inner class to access the outer class's instance methods ''directly'' as it is otherwise treated the same as a non-nested class. The only advantage it really offers is to encapsulate closely related classes under the one umbrella .
<syntaxhighlight lang="ecmascriptwren">class Outer {
static makeInner {
class Inner is Outer {
2,122

edits