<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" /> <meta name="generator" content="AsciiDoc 8.6.5" /> <title>Listing of doc/example-scripts/per-object-mixins.tcl</title> <style type="text/css"> /* Shared CSS for AsciiDoc xhtml11 and html5 backends */ /* Default font. */ body { font-family: Georgia,serif; } /* Title font. */ h1, h2, h3, h4, h5, h6, div.title, caption.title, thead, p.table.header, #toctitle, #author, #revnumber, #revdate, #revremark, #footer { font-family: Arial,Helvetica,sans-serif; } body { margin: 1em 5% 1em 5%; } a { color: blue; text-decoration: underline; } a:visited { color: fuchsia; } em { font-style: italic; color: navy; } strong { font-weight: bold; color: #083194; } h1, h2, h3, h4, h5, h6 { color: #527bbd; margin-top: 1.2em; margin-bottom: 0.5em; line-height: 1.3; } h1, h2, h3 { border-bottom: 2px solid silver; } h2 { padding-top: 0.5em; } h3 { float: left; } h3 + * { clear: left; } h5 { font-size: 1.0em; } div.sectionbody { margin-left: 0; } hr { border: 1px solid silver; } p { margin-top: 0.5em; margin-bottom: 0.5em; } ul, ol, li > p { margin-top: 0; } ul > li { color: #aaa; } ul > li > * { color: black; } pre { padding: 0; margin: 0; } #author { color: #527bbd; font-weight: bold; font-size: 1.1em; } #email { } #revnumber, #revdate, #revremark { } #footer { font-size: small; border-top: 2px solid silver; padding-top: 0.5em; margin-top: 4.0em; } #footer-text { float: left; padding-bottom: 0.5em; } #footer-badges { float: right; padding-bottom: 0.5em; } #preamble { margin-top: 1.5em; margin-bottom: 1.5em; } div.imageblock, div.exampleblock, div.verseblock, div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, div.admonitionblock { margin-top: 1.0em; margin-bottom: 1.5em; } div.admonitionblock { margin-top: 2.0em; margin-bottom: 2.0em; margin-right: 10%; color: #606060; } div.content { /* Block element content. */ padding: 0; } /* Block element titles. */ div.title, caption.title { color: #527bbd; font-weight: bold; text-align: left; margin-top: 1.0em; margin-bottom: 0.5em; } div.title + * { margin-top: 0; } td div.title:first-child { margin-top: 0.0em; } div.content div.title:first-child { margin-top: 0.0em; } div.content + div.title { margin-top: 0.0em; } div.sidebarblock > div.content { background: #ffffee; border: 1px solid #dddddd; border-left: 4px solid #f0f0f0; padding: 0.5em; } div.listingblock > div.content { border: 1px solid #dddddd; border-left: 5px solid #f0f0f0; background: #f8f8f8; padding: 0.5em; } div.quoteblock, div.verseblock { padding-left: 1.0em; margin-left: 1.0em; margin-right: 10%; border-left: 5px solid #f0f0f0; color: #777777; } div.quoteblock > div.attribution { padding-top: 0.5em; text-align: right; } div.verseblock > pre.content { font-family: inherit; font-size: inherit; } div.verseblock > div.attribution { padding-top: 0.75em; text-align: left; } /* DEPRECATED: Pre version 8.2.7 verse style literal block. */ div.verseblock + div.attribution { text-align: left; } div.admonitionblock .icon { vertical-align: top; font-size: 1.1em; font-weight: bold; text-decoration: underline; color: #527bbd; padding-right: 0.5em; } div.admonitionblock td.content { padding-left: 0.5em; border-left: 3px solid #dddddd; } div.exampleblock > div.content { border-left: 3px solid #dddddd; padding-left: 0.5em; } div.imageblock div.content { padding-left: 0; } span.image img { border-style: none; } a.image:visited { color: white; } dl { margin-top: 0.8em; margin-bottom: 0.8em; } dt { margin-top: 0.5em; margin-bottom: 0; font-style: normal; color: navy; } dd > *:first-child { margin-top: 0.1em; } ul, ol { list-style-position: outside; } ol.arabic { list-style-type: decimal; } ol.loweralpha { list-style-type: lower-alpha; } ol.upperalpha { list-style-type: upper-alpha; } ol.lowerroman { list-style-type: lower-roman; } ol.upperroman { list-style-type: upper-roman; } div.compact ul, div.compact ol, div.compact p, div.compact p, div.compact div, div.compact div { margin-top: 0.1em; margin-bottom: 0.1em; } tfoot { font-weight: bold; } td > div.verse { white-space: pre; } div.hdlist { margin-top: 0.8em; margin-bottom: 0.8em; } div.hdlist tr { padding-bottom: 15px; } dt.hdlist1.strong, td.hdlist1.strong { font-weight: bold; } td.hdlist1 { vertical-align: top; font-style: normal; padding-right: 0.8em; color: navy; } td.hdlist2 { vertical-align: top; } div.hdlist.compact tr { margin: 0; padding-bottom: 0; } .comment { background: yellow; } .footnote, .footnoteref { font-size: 0.8em; } span.footnote, span.footnoteref { vertical-align: super; } #footnotes { margin: 20px 0 20px 0; padding: 7px 0 0 0; } #footnotes div.footnote { margin: 0 0 5px 0; } #footnotes hr { border: none; border-top: 1px solid silver; height: 1px; text-align: left; margin-left: 0; width: 20%; min-width: 100px; } div.colist td { padding-right: 0.5em; padding-bottom: 0.3em; vertical-align: top; } div.colist td img { margin-top: 0.3em; } @media print { #footer-badges { display: none; } } #toc { margin-bottom: 2.5em; } #toctitle { color: #527bbd; font-size: 1.1em; font-weight: bold; margin-top: 1.0em; margin-bottom: 0.1em; } div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { margin-top: 0; margin-bottom: 0; } div.toclevel2 { margin-left: 2em; font-size: 0.9em; } div.toclevel3 { margin-left: 4em; font-size: 0.9em; } div.toclevel4 { margin-left: 6em; font-size: 0.9em; } span.aqua { color: aqua; } span.black { color: black; } span.blue { color: blue; } span.fuchsia { color: fuchsia; } span.gray { color: gray; } span.green { color: green; } span.lime { color: lime; } span.maroon { color: maroon; } span.navy { color: navy; } span.olive { color: olive; } span.purple { color: purple; } span.red { color: red; } span.silver { color: silver; } span.teal { color: teal; } span.white { color: white; } span.yellow { color: yellow; } span.aqua-background { background: aqua; } span.black-background { background: black; } span.blue-background { background: blue; } span.fuchsia-background { background: fuchsia; } span.gray-background { background: gray; } span.green-background { background: green; } span.lime-background { background: lime; } span.maroon-background { background: maroon; } span.navy-background { background: navy; } span.olive-background { background: olive; } span.purple-background { background: purple; } span.red-background { background: red; } span.silver-background { background: silver; } span.teal-background { background: teal; } span.white-background { background: white; } span.yellow-background { background: yellow; } span.big { font-size: 2em; } span.small { font-size: 0.6em; } span.underline { text-decoration: underline; } span.overline { text-decoration: overline; } span.line-through { text-decoration: line-through; } /* * xhtml11 specific * * */ tt { font-family: monospace; font-size: inherit; color: navy; } div.tableblock { margin-top: 1.0em; margin-bottom: 1.5em; } div.tableblock > table { border: 3px solid #527bbd; } thead, p.table.header { font-weight: bold; color: #527bbd; } p.table { margin-top: 0; } /* Because the table frame attribute is overriden by CSS in most browsers. */ div.tableblock > table[frame="void"] { border-style: none; } div.tableblock > table[frame="hsides"] { border-left-style: none; border-right-style: none; } div.tableblock > table[frame="vsides"] { border-top-style: none; border-bottom-style: none; } /* * html5 specific * * */ .monospaced { font-family: monospace; font-size: inherit; color: navy; } table.tableblock { margin-top: 1.0em; margin-bottom: 1.5em; } thead, p.tableblock.header { font-weight: bold; color: #527bbd; } p.tableblock { margin-top: 0; } table.tableblock { border-width: 3px; border-spacing: 0px; border-style: solid; border-color: #527bbd; border-collapse: collapse; } th.tableblock, td.tableblock { border-width: 1px; padding: 4px; border-style: solid; border-color: #527bbd; } table.tableblock.frame-topbot { border-left-style: hidden; border-right-style: hidden; } table.tableblock.frame-sides { border-top-style: hidden; border-bottom-style: hidden; } table.tableblock.frame-none { border-style: hidden; } th.tableblock.halign-left, td.tableblock.halign-left { text-align: left; } th.tableblock.halign-center, td.tableblock.halign-center { text-align: center; } th.tableblock.halign-right, td.tableblock.halign-right { text-align: right; } th.tableblock.valign-top, td.tableblock.valign-top { vertical-align: top; } th.tableblock.valign-middle, td.tableblock.valign-middle { vertical-align: middle; } th.tableblock.valign-bottom, td.tableblock.valign-bottom { vertical-align: bottom; } </style> <script type="text/javascript"> /*<+'])'); // Function that scans the DOM tree for header elements (the DOM2 // nodeIterator API would be a better technique but not supported by all // browsers). var iterate = function (el) { for (var i = el.firstChild; i != null; i = i.nextSibling) { if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { var mo = re.exec(i.tagName); if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { result[result.length] = new TocEntry(i, getText(i), mo[1]-1); } iterate(i); } } } iterate(el); return result; } var toc = document.getElementById("toc"); if (!toc) { return; } // Delete existing TOC entries in case we're reloading the TOC. var tocEntriesToRemove = []; var i; for (i = 0; i < toc.childNodes.length; i++) { var entry = toc.childNodes[i]; if (entry.nodeName == 'DIV' && entry.getAttribute("class") && entry.getAttribute("class").match(/^toclevel/)) tocEntriesToRemove.push(entry); } for (i = 0; i < tocEntriesToRemove.length; i++) { toc.removeChild(tocEntriesToRemove[i]); } // Rebuild TOC entries. var entries = tocEntries(document.getElementById("content"), toclevels); for (var i = 0; i < entries.length; ++i) { var entry = entries[i]; if (entry.element.id == "") entry.element.id = "_toc_" + i; var a = document.createElement("a"); a.href = "#" + entry.element.id; a.appendChild(document.createTextNode(entry.text)); var div = document.createElement("div"); div.appendChild(a); div.className = "toclevel" + entry.toclevel; toc.appendChild(div); } if (entries.length == 0) toc.parentNode.removeChild(toc); }, ///////////////////////////////////////////////////////////////////// // Footnotes generator ///////////////////////////////////////////////////////////////////// /* Based on footnote generation code from: * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html */ footnotes: function () { // Delete existing footnote entries in case we're reloading the footnodes. var i; var noteholder = document.getElementById("footnotes"); if (!noteholder) { return; } var entriesToRemove = []; for (i = 0; i < noteholder.childNodes.length; i++) { var entry = noteholder.childNodes[i]; if (entry.nodeName == 'DIV' && entry.getAttribute("class") == "footnote") entriesToRemove.push(entry); } for (i = 0; i < entriesToRemove.length; i++) { noteholder.removeChild(entriesToRemove[i]); } // Rebuild footnote entries. var cont = document.getElementById("content"); var spans = cont.getElementsByTagName("span"); var refs = {}; var n = 0; for (i=0; i<spans.length; i++) { if (spans[i].className == "footnote") { n++; var note = spans[i].getAttribute("data-note"); if (!note) { // Use [\s\S] in place of . so multi-line matches work. // Because JavaScript has no s (dotall) regex flag. note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; spans[i].innerHTML = "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + "' title='View footnote' class='footnote'>" + n + "</a>]"; spans[i].setAttribute("data-note", note); } noteholder.innerHTML += "<div class='footnote' id='_footnote_" + n + "'>" + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + n + "</a>. " + note + "</div>"; var id =spans[i].getAttribute("id"); if (id != null) refs["#"+id] = n; } } if (n == 0) noteholder.parentNode.removeChild(noteholder); else { // Process footnoterefs. for (i=0; i<spans.length; i++) { if (spans[i].className == "footnoteref") { var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); href = href.match(/#.*/)[0]; // Because IE return full URL. n = refs[href]; spans[i].innerHTML = "[<a href='#_footnote_" + n + "' title='View footnote' class='footnote'>" + n + "</a>]"; } } } }, install: function(toclevels) { var timerId; function reinstall() { asciidoc.footnotes(); if (toclevels) { asciidoc.toc(toclevels); } } function reinstallAndRemoveTimer() { clearInterval(timerId); reinstall(); } timerId = setInterval(reinstall, 500); if (document.addEventListener) document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false); else window.onload = reinstallAndRemoveTimer; } } asciidoc.install(); /*]]>*/ </script> </head> <body class="article"> <div id="header"> <h1>Listing of doc/example-scripts/per-object-mixins.tcl</h1> </div> <div id="content"> <div id="preamble"> <div class="sectionbody"> <div class="paragraph"><p>NX supports "open class definitions", object specific behavior and mixin classes (among other things) to achieve dynamic behavior extensions. The so-called per-object mixins are actually an implementation of the decorator pattern.</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'><span class='nx-keyword'>package</span> req nx</pre></div></div> <div class="paragraph"><p>Here is the original example: a method from a derived class extends the behavior of the baseclass; the primitive "next" calls other same-named methods. In the example below, the baseclass method "speak" is called at the beginning of the derived-class method. The primitive "next" can be placed at arbitrary places, or it can be omitted when the baseclass method should not be called.</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'><span class='nx-keyword'>nx::Class</span> <span class='nx-keyword'>create</span> BaseClass { :<span class='nx-keyword'>public</span> <span class='nx-keyword'>method</span> speak {} { <span class='nx-keyword'>puts</span> <span class='nx-string'>"Hello from BC."</span> } } <span class='nx-keyword'>nx::Class</span> <span class='nx-keyword'>create</span> DerivedClass -<span class='nx-keyword'>superclass</span> BaseClass { :<span class='nx-keyword'>public</span> <span class='nx-keyword'>method</span> speak {} { <span class='nx-keyword'>next</span> <span class='nx-keyword'>puts</span> <span class='nx-string'>"Hello from DC."</span> } } DerivedClass <span class='nx-keyword'>create</span> o1 o1 speak</pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> Hello from BC. Hello from DC.</tt></pre> </div></div> <div class="paragraph"><p>There are many ways to extend the behavior NX classes at runtime. The easiest thing is to add methods dynamically to classes. E.g. we can extend the BaseClass with the method unknown, which is called whenever an unknown method is called.</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>BaseClass <span class='nx-keyword'>method</span> unknown {m args} { <span class='nx-keyword'>puts</span> <span class='nx-string'>"What? $m? I don't understand."</span> } o1 sing</pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> What? sing? I don't understand.</tt></pre> </div></div> <div class="paragraph"><p>Often, you do not want to extend the class, but to modify the behavior of a single object. In NX, an object can have individual methods:</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>o1 <span class='nx-keyword'>public</span> <span class='nx-keyword'>method</span> sing {} { <span class='nx-keyword'>puts</span> <span class='nx-string'>"Ok, here it goes: Lala Lala!"</span> } o1 sing</pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> Ok, here it goes: Lala Lala!</tt></pre> </div></div> <div class="paragraph"><p>In many situations, it is desired to add/remove a set of methods dynamically to objects or classes. The mechanisms above allow this, but they are rather cumbersome and do support a systematic behavior engineering. One can add so-called "mixin classes" to objects and/or classes. For example, we can define a class M for a more verbose methods:</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'><span class='nx-keyword'>nx::Class</span> <span class='nx-keyword'>create</span> M { :<span class='nx-keyword'>public</span> <span class='nx-keyword'>method</span> sing {} { <span class='nx-keyword'>puts</span> -nonewline <span class='nx-string'>"[self] sings: "</span> <span class='nx-keyword'>next</span> } :<span class='nx-keyword'>method</span> unknown args { <span class='nx-keyword'>puts</span> -nonewline <span class='nx-string'>"[self] is confused: "</span> <span class='nx-keyword'>next</span> } }</pre></div></div> <div class="paragraph"><p>The behavior of M can be mixed into the behavior of o1 through per object mixins …</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>o1 <span class='nx-keyword'>mixin</span> M</pre></div></div> <div class="olist lowerroman"><ol class="lowerroman"> <li> <p> and we call the methods again: </p> </li> </ol></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>o1 sing o1 <span class='nx-keyword'>read</span></pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> ::o1 sings: Ok, here it goes: Lala Lala! ::o1 is confused: What? read? I don't understand.</tt></pre> </div></div> <div class="paragraph"><p>We can remove the new behavior easily by unregistering the mixin class ….</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>o1 <span class='nx-keyword'>mixin</span> <span class='nx-string'>""</span></pre></div></div> <div class="olist lowerroman"><ol class="lowerroman"> <li> <p> and we call the methods again: </p> </li> </ol></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>o1 sing o1 <span class='nx-keyword'>read</span></pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> Ok, here it goes: Lala Lala! What? read? I don't understand.</tt></pre> </div></div> <div class="paragraph"><p>Mixin classes can be used to extend the behavior of classes as well.</p></div> <div class="listingblock"> <div class="content"><style type='text/css'> .nx {color: #000000; font-weight: normal; font-style: normal; padding-left: 10px} table.nx {border-collapse: collapse; border-spacing: 3px;} .nx-linenr {border-right: 1px solid #DDDDDD;padding-right: 5px; color: #2B547D;font-style: italic;} .nx-string {color: #779977; font-weight: normal; font-style: italic;} .nx-comment {color: #717ab3; font-weight: normal; font-style: italic;} .nx-keyword {color: #7f0055; font-weight: normal; font-style: normal;} .nx-placeholder {color: #AF663F; font-weight: normal; font-style: italic;} .nx-variable {color: #AF663F; font-weight: normal; font-style: normal;} </style> <pre class='nx'>BaseClass <span class='nx-keyword'>mixin</span> M o1 sing o1 <span class='nx-keyword'>read</span> DerivedClass <span class='nx-keyword'>create</span> o2 o2 <span class='nx-keyword'>read</span></pre></div></div> <div class="paragraph"><p>The output is:</p></div> <div class="listingblock"> <div class="content"> <pre><tt> ::o1 sings: Ok, here it goes: Lala Lala! ::o1 is confused: What? read? I don't understand. ::o2 is confused: What? read? I don't understand.</tt></pre> </div></div> </div> </div> </div> <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> Last updated 2011-09-19 03:46:57 CEST </div> </div> </body> </html>