objects with no ancestor are not implicitely final

This commit is contained in:
Araq 2012-08-24 17:33:04 +02:00
commit d17caa86e8
15 changed files with 44 additions and 22 deletions

View file

@ -305,7 +305,7 @@ type
tyBigNum, tyBigNum,
tyConst, tyMutable, tyVarargs, tyConst, tyMutable, tyVarargs,
tyIter, # unused tyIter, # unused
tyProxy # currently unused tyProxy # used as errornous type (for idetools)
tyTypeClass, tyTypeClass,
const const
@ -328,10 +328,11 @@ type
nfSem # node has been checked for semantics nfSem # node has been checked for semantics
TNodeFlags* = set[TNodeFlag] TNodeFlags* = set[TNodeFlag]
TTypeFlag* = enum # keep below 15 for efficiency reasons (now: 13) TTypeFlag* = enum # keep below 15 for efficiency reasons (now: 14)
tfVarargs, # procedure has C styled varargs tfVarargs, # procedure has C styled varargs
tfNoSideEffect, # procedure type does not allow side effects tfNoSideEffect, # procedure type does not allow side effects
tfFinal, # is the object final? tfFinal, # is the object final?
tfInheritable, # is the object inheritable?
tfAcyclic, # type is acyclic (for GC optimization) tfAcyclic, # type is acyclic (for GC optimization)
tfEnumHasHoles, # enum cannot be mapped into a range tfEnumHasHoles, # enum cannot be mapped into a range
tfShallow, # type can be shallow copied on assignment tfShallow, # type can be shallow copied on assignment

View file

@ -57,6 +57,7 @@ proc InitDefines*() =
DefineSymbol("nimrod") # 'nimrod' is always defined DefineSymbol("nimrod") # 'nimrod' is always defined
# for bootstrapping purposes and old code: # for bootstrapping purposes and old code:
DefineSymbol("nimhygiene") DefineSymbol("nimhygiene")
DefineSymbol("niminheritable")
# add platform specific symbols: # add platform specific symbols:
case targetCPU case targetCPU

View file

@ -48,7 +48,7 @@ const
typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl,
wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow, wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow,
wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef, wImportcpp, wImportobjc, wError, wIncompleteStruct, wByCopy, wByRef,
wGenSym, wInject} wInheritable, wGenSym, wInject}
fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern,
wImportcpp, wImportobjc, wError} wImportcpp, wImportobjc, wError}
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
@ -584,6 +584,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
noVal(it) noVal(it)
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)
else: incl(sym.typ.flags, tfFinal) else: incl(sym.typ.flags, tfFinal)
of wInheritable:
noVal(it)
if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it)
else: incl(sym.typ.flags, tfInheritable)
of wAcyclic: of wAcyclic:
noVal(it) noVal(it)
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)

View file

@ -545,6 +545,8 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c) var s = newSymS(skType, newIdentNode(getIdent("dummy"), n.info), c)
s.typ = result s.typ = result
pragma(c, s, n.sons[0], typePragmas) pragma(c, s, n.sons[0], typePragmas)
if base == nil and tfInheritable notin result.flags:
incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}: if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:

View file

@ -970,9 +970,10 @@ in future versions of the compiler.
person = ("Peter", 30) person = ("Peter", 30)
The implementation aligns the fields for best access performance. The alignment The implementation aligns the fields for best access performance. The alignment
is compatible with the way the C compiler does it. For consistency is compatible with the way the C compiler does it.
with ``object`` declarations, tuples in a ``type`` section can also be defined
with indentation instead of ``[]``: For consistency with ``object`` declarations, tuples in a ``type`` section
can also be defined with indentation instead of ``[]``:
.. code-block:: nimrod .. code-block:: nimrod
@ -988,7 +989,7 @@ the ``of`` operator can be used to determine the object's type.
.. code-block:: nimrod .. code-block:: nimrod
type type
TPerson = object TPerson {.inheritable.} = object
name*: string # the * means that `name` is accessible from other modules name*: string # the * means that `name` is accessible from other modules
age: int # no * means that the field is hidden age: int # no * means that the field is hidden
@ -1002,7 +1003,9 @@ the ``of`` operator can be used to determine the object's type.
Object fields that should be visible from outside the defining module, have to Object fields that should be visible from outside the defining module, have to
be marked by ``*``. In contrast to tuples, different object types are be marked by ``*``. In contrast to tuples, different object types are
never *equivalent*. never *equivalent*. Objects that have no ancestor are implicitely ``final``
and thus have no hidden type field. One can use the ``inheritable`` pragma to
introduce new object roots apart from ``system.TObject``.
Object variants Object variants

View file

@ -74,7 +74,11 @@ section.
Inheritance is done with the ``object of`` syntax. Multiple inheritance is Inheritance is done with the ``object of`` syntax. Multiple inheritance is
currently not supported. If an object type has no suitable ancestor, ``TObject`` currently not supported. If an object type has no suitable ancestor, ``TObject``
can be used as its ancestor, but this is only a convention. can be used as its ancestor, but this is only a convention. Objects that have
no ancestor are implicitely ``final``. You can use the ``inheritable`` pragma
to introduce new object roots apart from ``system.TObject``. (This is used
in the GTK wrapper for instance.)
**Note**: Composition (*has-a* relation) is often preferable to inheritance **Note**: Composition (*has-a* relation) is often preferable to inheritance
(*is-a* relation) for simple code reuse. Since objects are value types in (*is-a* relation) for simple code reuse. Since objects are value types in

View file

@ -1057,7 +1057,7 @@ type
charset: set[char] ## if kind == tkCharSet charset: set[char] ## if kind == tkCharSet
index: int ## if kind == tkBackref index: int ## if kind == tkBackref
TPegLexer = object ## the lexer object. TPegLexer {.inheritable.} = object ## the lexer object.
bufpos: int ## the current position within the buffer bufpos: int ## the current position within the buffer
buf: cstring ## the buffer itself buf: cstring ## the buffer itself
LineNumber: int ## the current line number LineNumber: int ## the current line number

View file

@ -58,7 +58,7 @@ type
Features: seq[Feature] # Read-Only Features: seq[Feature] # Read-Only
PNode* = ref Node PNode* = ref Node
Node = object Node = object of TObject
attributes*: seq[PAttr] attributes*: seq[PAttr]
childNodes*: seq[PNode] childNodes*: seq[PNode]
FLocalName: string # Read-only FLocalName: string # Read-only

View file

@ -171,9 +171,12 @@ proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} =
proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} = proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} =
result = value >= s.a and value <= s.b result = value >= s.a and value <= s.b
when not defined(niminheritable):
{.pragma: inheritable.}
when not defined(EcmaScript) and not defined(NimrodVM): when not defined(EcmaScript) and not defined(NimrodVM):
type type
TGenericSeq {.compilerproc, pure.} = object TGenericSeq {.compilerproc, pure, inheritable.} = object
len, reserved: int len, reserved: int
PGenericSeq {.exportc.} = ptr TGenericSeq PGenericSeq {.exportc.} = ptr TGenericSeq
# len and space without counting the terminating zero: # len and space without counting the terminating zero:
@ -197,7 +200,7 @@ type
## is an int type ranging from one to the maximum value ## is an int type ranging from one to the maximum value
## of an int. This type is often useful for documentation and debugging. ## of an int. This type is often useful for documentation and debugging.
TObject* {.exportc: "TNimObject".} = TObject* {.exportc: "TNimObject", inheritable.} =
object ## the root of Nimrod's object hierarchy. Objects should object ## the root of Nimrod's object hierarchy. Objects should
## inherit from TObject or one of its descendants. However, ## inherit from TObject or one of its descendants. However,
## objects that have no ancestor are allowed. ## objects that have no ancestor are allowed.

View file

@ -113,7 +113,7 @@ type
PChunk = ptr TBaseChunk PChunk = ptr TBaseChunk
PBigChunk = ptr TBigChunk PBigChunk = ptr TBigChunk
PSmallChunk = ptr TSmallChunk PSmallChunk = ptr TSmallChunk
TBaseChunk {.pure.} = object TBaseChunk {.pure, inheritable.} = object
prevSize: int # size of previous chunk; for coalescing prevSize: int # size of previous chunk; for coalescing
size: int # if < PageSize it is a small chunk size: int # if < PageSize it is a small chunk
used: bool # later will be optimized into prevSize... used: bool # later will be optimized into prevSize...

View file

@ -107,7 +107,7 @@ type
g_class*: PGTypeClass g_class*: PGTypeClass
PGTypeInterface* = ptr TGTypeInterface PGTypeInterface* = ptr TGTypeInterface
TGTypeInterface*{.pure.} = object TGTypeInterface*{.pure, inheritable.} = object
g_type*: GType g_type*: GType
g_instance_type*: GType g_instance_type*: GType
@ -993,7 +993,7 @@ proc plugin_complete_interface_info*(plugin: PGTypePlugin,
dynlib: gliblib, importc: "g_type_plugin_complete_interface_info".} dynlib: gliblib, importc: "g_type_plugin_complete_interface_info".}
type type
PGObject* = ptr TGObject PGObject* = ptr TGObject
TGObject*{.pure.} = object TGObject*{.pure, inheritable.} = object
g_type_instance*: TGTypeInstance g_type_instance*: TGTypeInstance
ref_count*: guint ref_count*: guint
qdata*: PGData qdata*: PGData
@ -1006,7 +1006,7 @@ type
TGWeakNotify* = proc (data: gpointer, where_the_object_was: PGObject){.cdecl.} TGWeakNotify* = proc (data: gpointer, where_the_object_was: PGObject){.cdecl.}
PGObjectConstructParam* = ptr TGObjectConstructParam PGObjectConstructParam* = ptr TGObjectConstructParam
PGObjectClass* = ptr TGObjectClass PGObjectClass* = ptr TGObjectClass
TGObjectClass*{.pure.} = object TGObjectClass*{.pure, inheritable.} = object
g_type_class*: TGTypeClass g_type_class*: TGTypeClass
construct_properties*: PGSList construct_properties*: PGSList
constructor*: proc (theType: GType, n_construct_properties: guint, constructor*: proc (theType: GType, n_construct_properties: guint,

View file

@ -341,7 +341,7 @@ type
float*: float64 float*: float64
imag*: float64 imag*: float64
TPyObject*{.pure.} = object TPyObject*{.pure, inheritable.} = object
ob_refcnt*: int ob_refcnt*: int
ob_type*: PPyTypeObject ob_type*: PPyTypeObject

View file

@ -1052,7 +1052,7 @@ type
charset: set[char] ## if kind == tkCharSet charset: set[char] ## if kind == tkCharSet
index: int ## if kind == tkBackref index: int ## if kind == tkBackref
TPegLexer = object ## the lexer object. TPegLexer {.inheritable.} = object ## the lexer object.
bufpos: int ## the current position within the buffer bufpos: int ## the current position within the buffer
buf: cstring ## the buffer itself buf: cstring ## the buffer itself
LineNumber: int ## the current line number LineNumber: int ## the current line number

View file

@ -1,13 +1,14 @@
version 0.9.0 version 0.9.0
============= =============
- ``final`` should be the default for objects
- implement "closure tuple consists of a single 'ref'" optimization - implement "closure tuple consists of a single 'ref'" optimization
- implement for loop transformation for first class iterators - implement for loop transformation for first class iterators
- implicit deref for parameter matching - implicit deref for parameter matching
- optimize genericAssign in the code generator - optimize genericAssign in the code generator
- the lookup rules for generics really are too permissive - the lookup rules for generics really are too permissive; global scope only
doesn't fly with closures though; for a start add a warning when processing
generic code
- fix remaining closure bugs: - fix remaining closure bugs:
- test evals.nim with closures - test evals.nim with closures
- what about macros with closures? - what about macros with closures?

View file

@ -108,6 +108,9 @@ Changes affecting backwards compatibility
- The Nimrod type system now distinguishes ``openarray`` from ``varargs``. - The Nimrod type system now distinguishes ``openarray`` from ``varargs``.
- Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old - Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old
behaviour. behaviour.
- Objects that have no ancestor are now implicitely ``final``. Use
the ``inheritable`` pragma to introduce new object roots apart
from ``TObject``.
Compiler Additions Compiler Additions