Programmering i Ruby

Den Pragmatiske Programmerers Veiledning

Forrige < Innhold ^
Neste >

Klasser og objekter



Klasser og objekter er åpenbart en sentral del av Ruby, men ved første øyekast kan de virke litt forvirrende. Det virker som om det er en menge konsepter: klasser, objekter, klasseobjekter, instansmetoder, klassemetoder og singleton-klasser. Men egentlig har Ruby bare en enkel klasse og objekt struktur, som vi vil diskutere i dette kapittelet. Faktisk er den grunnleggende modellen så enkel at vi kan beskrive den i en paragraf.

Et objekt har i Ruby tre kompontenter; et sett med flagg, noen instansvariable og en tilknytning til en klasse. En klasser er i Ruby et objekt av klassen Class, som inneholder alle de ting som etthvert objekt inneholder og i tillegg en liste over metoder og en referanse til superklassen (som igjen er en annen klasse). Alle metodekall i Ruby angir en mottaker (som per default er self, det gjeldene objektet). Ruby finner metoden som skal kalles ved å se i metodelisten i mottakerens klasse. Hvis den ikke finner metoden der, ser den i superklassen, og deretter i superklassens superklasse og så videre. Dersom metoden ikke er å finne i mottakerens klasse eller noen av dens foreldre, kaller Ruby method_missing metoden på det opprinnelige mottakerobjektet.

Det er alt---hele forklaringen. Videre til neste kapittel.

``Men vent'', roper du, ``Jeg har brukt hardt ervervede penger på dette kapittelet. Hva med alle disse andre greiene---singleton-klasser, klassemetoder og så videre. Hvordan virker de?''

Det er et godt spørsmål.

Hvordan klasser og objekter interagerer

Alle klasse/objekt interaksjoner kan forklares ved hjelp av den enkle modellen gir over: objekter refererer til klasser og klasser referer til null eller flere superklasser. Men implementasjonsdetaljene kan være litt vanskelige.

I vår erfaring har vi funnet at den enkleste måten å visualisere alt sammen er å tegne de faktiske objektene som Ruby implementerer. Så, i de følgende sidene vil vi se på alle de mulige kombinasjonene av klasser og objekter. Merk at dette ikke er klassediagrammer slik du kanskje kjenner dem fra UML; vi viser strukturer som eksisterer i minnet og pekere i mellom dem.

Et vanlig, dagligdags objekt

La oss begynne med en titt på et objekt laget utifra en enkel klasse. Figur 19.1 på side 239(??) viser et objekt referert til av en variabel, lucille, dernest objektets klasse, Guitar, og til slutt den klassens superklasse, Object. Legg merke til hvordan objektets klassereferanse (kalles klass av historiske årsaker som virkelig går Andy på nervene) peker til klasseobjektet, og hvordan super peker i fra den klassen til forelderklassen.

Figur 19.1: Et enkelt objekt, med dets klasse og superklasse.

Hvis vi kaller metoden lucille.play(), går Ruby til mottakeren, lucille og følger klass referansen frem til klasseobjektet til Guitar. Ruby søker i metodetabellen, finner play og kjører den. Hvis vi derimot kaller lucille.display, begynner Ruby på samme måte, men finner ikke display i metodetabellen til klassen Guitar. Deretter følges super referansen frem til Guitar sin superklasse, Object, hvor metoden blir funnet og kjørt.

Hva er meta?

Drevne lesere (ja, det vil si alle dere) vil ha lagt merke til at klass i Class objektene ikke peker til noe meningsfylt i Figur 19.1. Vi har nå al den informasjon til å finne ut hvor de burde peke.

Når du skriver lucille.play(), følger Ruby lucille sin klass peker for å finne et klasseobjekt hvor Ruby kan søke etter metoder. Så hva skjer når du kaller en klassemtode, slik som Guitar.strings(...)? Her er mottakeren klasseobjektet i seg selv, Guitar. Så, for å være konsekvent, må vi putte metodene i en annen klasse, refert til fra Guitar sin klass peker. Denne nye klassen vil inneholde alle klassemetodene til Guitar. Den kalles for en metaklasse. Vi vil angi metaklassen til Guitar som Guitar$'$. Men det er ikke den hele og fulle sannhet. Siden Guitar er en subklasse av Object, vil dens metaklasse Guitar$'$ være en subklasse av Object sin metaklasse, Object$'$. I figur 19.2 viser vi disse ekstra metaklassene.
Figur 19.2: Vi legger til en metaklasse til Guitar

Når Ruby utfører Guitar.strings() følges samme prosessen som nevnt tidligere: Ruby går til mottakeren, klassen Guitar, følger klass referansen til klassen Guitar$'$, og finner metoden.

Merk til slutt at en ``S'' har dukket opp i klaggene til klassen Guitar$'$. Klassene som Ruby lager automatisk merkes internt som singleton-klasser. Singleton-klasser behandles litt anderledes inne i Ruby. Det mest åpenbare forskjellen sett utenifra er at de er usynlige: de vil aldri dukke opp i en liste av objekter returnert fra sånne metoder som Module#ancestors eller ObjectSpace::each_object .

Objekt-spesifikke klasser

Ruby tillater deg å lage en klasse som er knyttet til ett spesifikt objekt. I det følgende eksempelet lager vi to String-objekter. Deretter assosierer vi en anonym klasse med en av dem, hvor vi overstyrer en av metodene i basisklassen samt legger til en ny metode.

a = "hello"
b = a.dup
class <<a
  def to_s
    "The value is '#{self}'"
  end
  def twoTimes
    self + self
  end
end
a.to_s » "The value is 'hello'"
a.twoTimes » "hellohello"
b.to_s » "hello"

Dette eksempelet bruker ``class << obj'' notasjonen, som kort og godt sier ``lag meg en ny klasse for objekt obj.'' We kunne også ha skrevet det som:

a = "hello"
b = a.dup
def a.to_s
  "The value is '#{self}'"
end
def a.twoTimes
  self + self
end
a.to_s » "The value is 'hello'"
a.twoTimes » "hellohello"
b.to_s » "hello"

Effekten er den samme i begge tilfeller: en klasse blir lagt til objektet ``a''. Dette gir oss en sterk pekepinn om hvordan Ruby implementerer dette: en singleton klasse blir generert og satt direkte inn som a sin klasse. Den opprinnelige klassen til a, String, blir superklassen til singleton-klassen. Før- og etter-bilder ser du i figure 19.3 på side 242(??).

Ruby gjør en liten optimalisering med disse singleton-klassene. Hvis et objekts klass referanse allerede peker til en singleton-klasse, blir det ikke laget en ny. Det betyr at den første av de to metodedefinisjonene i det forrige eksempelet vil lage en ny singleton-klasse, men den andre definisjonen vil kun legge en metode til i den eksisterende.

Figur 19.3: Å legge en singleton-klasse til et objekt.

Mixin moduler

Når en klasse inkluderer en modul, blir den modulens instansmetoder tilgjengelig som instansmetoder i klassern. Det er nesten som om modulen blir en superklasse til klassen som bruker den. Ikke overraskende da, at det er omtrent slik det fungerer. Når du inkluderer en modul, lager Ruby en anonym proxy-klasse som referer til modulen og setter proxy-klassen inn som den direkte superklassen til klassen som inkluderte modulen. Proxy-klassen inneholder referanser til instansvariablene og metodene til modulen. Dette er viktig: den samme modulen kan bli inkludert i mange forskjellige klasser og vil dukke opp i forskjellige arvehierarkier. Men takket være proxy-klassen, er det bare en underliggende modul: forandrer man en metodedefinisjon i modulen og det vil endre det i alle klasser som inkluderer den modulen, såvel de som alt har gjort det som de som kommer til å gjøre det.

module SillyModule
  def hello
    "Hello."
  end
end
class SillyClass
  include SillyModule
end
s = SillyClass.new
s.hello » "Hello."

module SillyModule
  def hello
    "Hi, there!"
  end
end
s.hello » "Hi, there!"

Forholdet mellom klasser og modulene de inkluderer vises i figur 19.4 på side 243(??). Hvis flere moduler inkluderes, blir de lagt til kjeden i tur og orden.

Figur 19.4: En inkludert modul og dens proxy klasse.

Dersom en modul selv inkluderer andre moduler, vil en kjede av proxy-klasser bli lagt til enhver klasse som inkluderer den modulen. En proxy for hver modul som direkte eller indirekte inkluderes.

Utvide objekter

På samme måte som du kan definere en anonym klasse for et objekt ved å bruke ``class <<obj '', kan du blande en modul inn i et objekt ved hjelp av Object#extend . For eksempel:

module Humor
  def tickle
    "hee, hee!"
  end
end
a = "Grouchy"
a.extend Humor
a.tickle » "hee, hee!"

Det er en interesant triks man kan gjøre med extend. Hvis du bruker metoden i en klassedefinisjon, blir modulens metoder klassemetoder.

module Humor
  def tickle
    "hee, hee!"
  end
end
class Grouchy
  include Humor
  extend  Humor
end
Grouchy.tickle » "hee, hee!"
a = Grouchy.new
a.tickle » "hee, hee!"

Dette skyldes at å kalle extend tilsvarer self.extend, slik at metodene blir lagt til self, som i en klassedefinisjon er selve klassen.

Klasse- og moduldefinisjoner

Etter en uttømmende titt på klasser og objekter, kan vi nå (heldigvis) komme til oss tilbake til programmering og se på bestanddelene som utgjør klasse- og moduldefinisjoner.

I språk som C++ og Java blir klassedefinisjoner prosessert ved kompilering: kompilatoren laster inn symboltabellene, finner ut hvor mye plass som trengs, og gjør alle disse andre obskure tingene vi helsti kke vil tenke for mye på.

Ruby er anderledes. I Ruby er klasse- og moduldefinisjoner kode som kan kjøres. Selv om de tolkes ved kompilering, blir klassene og modulene lagd ved kjøretid, når fortolkeren kommer til definisjonen. (Det samme gjelder metodedefinisjoner.) Dette tillater deg å strukturere programmene dine mye mer dynamisk enn i de fleste tradisjonelle språk. Du trenger bare gjøre valg en gang, når klassen blir definert, i stedet for hver gang objekter av den klassen blir brukt. Klassen i det neste eksempelet bestemmer seg når den blir definert hvilken versjon av dekrypteringsrutinen som skal lages.

class MediaPlayer
  include Tracing if $DEBUGGING

  if ::EXPORT_VERSION     def decrypt(stream)       raise "Decryption not available"     end   else     def decrypt(stream)       # ...     end   end

end

Dersom klassedefinisjoner er kjørbar kode, impliserer det også at de utføres i konteksten til et eller annet objekt: self må referere til et eller annet. La oss finne ut hva.

class Test
  puts "Type of self = #{self.type}"
  puts "Name of self = #{self.name}"
end
produserer:
Type of self = Class
Name of self = Test

Dette betyr at en klassedefinisjon er utført med den klassen som det gjeldende objekt. Hvis vi ser tilbake på avsnittet om metaklasser på side 238(??), legger vi merke til at det betyr at metoder i metaklassen og dens superklasser vil være tilgjengelig under kjøringen av metodedefinisjonen(klassedefinisjonen?). Vi kan prøve dette selv.

class Test
  def Test.sayHello
    puts "Hello from #{name}"
  end

  sayHello end
produserer:
Hello from Test

I dette eksempelet definerer vi en klassemetode, Test.sayHello, og deretter kaller den i kroppen til klassedefinisjonen. Fra sayHello kaller vi name, en instansmetode i klassen Module. Da Module er en forelder til Class, kan instansmetodene dens kalles uten en eksplisitt mottaker i fra en klassedefinisjon.

Faktisk så er mange av de direktivene du bruker når du definerer en klasse eller modul, slik som alias_method, attr, and public, ikke noe mer enn metoder i klassen Module. Dette åpner opp for noen interessante muligheter---du kan utvide funksjonaliteten til klasse- og moduldefinisjoner ved hjelp av Ruby kode. La oss se på noen eksempler.

Første eksempelet ser på hvordan vi kan legge til en enkel dokumenteringsfasilitet til moduler og klasser. Dette vil tillate oss å assosiere en streng med moduler og klasser som vi skriver. Denne strengen vil være tilgjengelig mens programmet kjører. Vi velger en enkel syntaks.

class Example
  doc "This is a sample documentation string"
  # .. rest of class
end

Vi trenger å gjøre doc tilgjengelig for alle moduler og klasser, så vi må gjøre den om til en instansmetode i Module-klassen.

class Module
  @@docs = Hash.new(nil)
  def doc(str)
    @@docs[self.name] = str
  end

  def Module::doc(aClass)     # If we're passed a class or module, convert to string     # ('<=' for classes checks for same class or subtype)     aClass = aClass.name if aClass.type <= Module     @@docs[aClass] || "No documentation for #{aClass}"   end end

class Example   doc "This is a sample documentation string"   # .. rest of class end

module Another   doc <<-edoc     And this is a documentation string     in a module   edoc   # rest of module end

puts Module::doc(Example) puts Module::doc("Another")
produserer:
This is a sample documentation string
      And this is a documentation string
      in a module

Det andre eksempelet er en ytelsesforbedring basert på Tadayoshi Funaba sin date-modul (beskrivelse starter på side 439(??)). La oss si at vi har en klasse som representerer en eller annen grunnleggende kvantitet (i dette tilfellet, en dato). Klassen kan ha mange attributter som presenterer den samme underliggende datoen på forskjellige måter: som et Julian dagnummer, som en streng, som en [år, måned, dag] trio av verdier og så videre. Hver verdi representerer den samme datoen og det kan kreves en ganske komplisert utregning for å finne verdien. Vi ønsker derfor å bare regne ut hver attribut en gang, når den først aksesseres.

Måten å gjøre det på egen hånd, er å legge en test til hver aksessor:

class ExampleDate
  def initialize(dayNumber)
    @dayNumber = dayNumber
  end

  def asDayNumber     @dayNumber   end

  def asString     unless @string       # complex calculation       @string = result     end     @string   end

  def asYMD     unless @ymd       # another calculation       @ymd = [ y, m, d ]     end     @ymd   end   # ... end

Dette er en kjeitete måte å gjøre det på---la oss se om vi ikke kan komme frem til noe mer elegant.

Det vi tar sikte på, er et direktiv som indikerer at kroppen til en gitt metode kun skal kalles en gang. Verdien som returneres fra det første kallet skal lagres (caches). Deretter skal senere kall til samme metode bare returnere den lagrede verdien uten å reevaluere metodekroppen igjen. Dette ligner litt på Eiffel sin once modifikator for rutinger. Vi vil gjerne kunne skrive noe slikt:

class ExampleDate
  def asDayNumber
    @dayNumber
  end

  def asString     # complex calculation   end

  def asYMD     # another calculation     [ y, m, d ]   end

  once :asString, :asYMD end

Vi kan bruke once som et direktiv ved å skrive det som en klassemeteode i ExampleDate, men hvordan vil det se ut internt? Trikset er å få den til å omskrive metodene som den får navnene på. For hver metode, lager direktivet et alias for den gamle koden og en ny metode med det samme navnet. Den nye metoden gjør to ting. Først kaller den den opprinnelige metoden (ved hjelp av aliaset) og lagrer den resulterende verdien i en instansvariabel. Deretter redefinerer den seg selv, slik at senere kall ganske enkelt returnerer instansvariabelen direkte. Her følger Tadayoshi Funaba sin kode, med noen små omformatteringer.

def ExampleDate.once(*ids)
  for id in ids
    module_eval <<-"end_eval"
      alias_method :__#{id.to_i}__, #{id.inspect}
      def #{id.id2name}(*args, &block)
        def self.#{id.id2name}(*args, &block)
          @__#{id.to_i}__
        end
        @__#{id.to_i}__ = __#{id.to_i}__(*args, &block)
      end
    end_eval
  end
end

Denne koden bruker module_eval for å utføre en blokk med kode i konteksten til den kallende modulen (eller, som her, den kallende klassen). Den opprinnelige metoden får nytt navn på formen __nnn__, hvor nnn byttes ut med den heltallige representasjonen av metodenavnets symbolske identifikator. Koden bruker det samme navnet for lagring (caching) av den utregnede verdien i en instansvariabel. mesteparten av koden er en metode som dynamisk redefinerer seg selv. Legg merke til at denne redefinsisjonen benytter seg av det faktum at metoder kan inneholde nøstede singleton-metodedefinisjoner, som er et lurt knep.

Forstår du denne koden er du på god vei til å bli en Ruby mester.

Men, vi kan ta det enda lengre. Titt på date modulen og du vil se metoden once skrevet litt anderledes.

class Date
  class << self
    def once(*ids)
      # ...
    end
  end
  # ...
end

Det interessante her er den indre klassedefinisjonen, ``class << self''. Dette definerer en klasse basert på objektet self, som tilfeldigvis er klasseobjektet til Date. Resultatet? En hver metode inne i den indre klassedefinisjonen blir automatisk en klassemetode i Date.

Metoden med once er generelt brukbar---den bør fungere for en hver klasse. Dersom du tok once og gjorde den om til en privat instansmetode i Module-klassen, ville den være tilgjengelig for alle Ruby klasser.

Klassenavn er konstanter

Vi har tidligere sagt at når du kaller en klassemetode, er alt som skjer at en beskjed sendes til Class objektet. Når du skriver noe slikt som String.new("gumby"), sender du beskjeden new til objektet som er klassen String. Men hvordan vet Ruby at det er det som skal gjøres? Tross alt burde mottakeren av meldingen være en objektreferanse, hvilket impliserer at der må være en konstant kalt ``String'' et sted som referer til String-klasseobjektet. [ Det vil være en konstant, ikke en variabel, da ``String'' begynner med stor bokstav. ] Dette er faktisk det som skjer. Alle innebygde klasser, sammen med klasser du definerer, har en tilsvarende global konstant med samme navn som klassen. Dette er enkelt og greitt, men samtidig litt subtilt. Subtilit fordi det er faktisk to ting vi kaller (for eksempel) String i systemet. Der er en konstant som referer til klasseobjektet String, og selve klasseobjektet.

Det faktum at klassenavn bare er konstanter betyr at du kan behandle klasser som et hvert annet Ruby objekt: du kan kopiere dem, sende dem inn som argument til metoder og bruke dem i uttrykk.

def factory(klass, *args)
  klass.new(*args)
end
factory(String, "Hello") » "Hello"
factory(Dir,    ".") » #<Dir:0x401b3234>
flag = true
(flag ? Array : Hash)[1, 2, 3, 4] » [1, 2, 3, 4]
flag = false
(flag ? Array : Hash)[1, 2, 3, 4] » {1=>2, 3=>4}

Toppnivå utføringsmiljø

Mang en gang har vi i denne boken påstått at alt i Ruby er et objekt. Men det er en ting vi har brukt igjen og igjen som tilsynelatende går imot dette---Ruby sitt toppnivå utføringsmiljø.

puts "Hello, World"

Ikke et objekt i sikte. Vi kunne like godt holdt på å skrive i en variant av Fortran eller QW-Basic. Men grav dypere og du vil finne objekter og klasser gjemt i selv den enkleste kode.

Vi vet at litteralen "Hello, World" genererer et String-objekt, så der har vi ett objekt. Vi vet også at det nakne metodekallet til puts tilsvarer self.puts. Men hva er ``self'' her?

self.type » Object

På toppnivå kjører vi kode i konteksten til et eller annet forhåndsdefinert objekt. Når vi definerer metoder, lager vi faktisk (private) singletonmetoder for dette objektet. Instansvariabler tilhører dette objeket. Og siden vi er i konteksten til Object, kan vi kalle alle metodene til Object (deriblant de blandet inn fra Kernel) på funksjonsform. Dette forklarer hvorfor vi kan kalle Kernel metoder, slik som puts, på toppnivå (og for den saks skyld, over alt i Ruby): disse metodene er en del av et hvert objekt.

Arv og synlighet

Det er en siste ting å nevne med arv, og det er temmelig obskurt.

Inne i en klassedefinisjon kan du forandre synligheten til en metode i en forelder klasse. For eksempel, kan du gjøre noe slikt:

class Base
  def aMethod
    puts "Got here"
  end
  private :aMethod
end

class Derived1 < Base   public :aMethod end

class Derived2 < Base end

I dette eksempelet vil du kunne kalle aMethod på instanser av klasse Derived1, men ikke på instanser av Base eller Derived2.

Så hvordan klarer Ruby å ha en metode med to forskjellige grader av synlighet? Kort fortalt, ved å jukse.

Dersom en subklasse forandrer synligheten til en metode i en forelder, setter Ruby inn en gjemt proxy metode i subklassen som kaller den opprinnelige metoden via super. Deretter setter Ruby synligheten til den proxymetoden til hva en du ba om. Det betyr at følgende kode:

class Derived1 < Base
  public :aMethod
end

gjør det samme som:

class Derived1 < Base
  def aMethod(*args)
    super
  end
  public :aMethod
end

Kallet til super kan få tilgang til forelderens metode uansett synlighet, så omskrivingen gjør det mulig for subklassen å overstyre forelderens synlighetsregler. Skumle saker, eller hva?

Fryse objekter

Noen ganger har du arbeidet lenge med å gjøre objektet ditt akkurat slik du vil ha det og ikke søren om du vil la hvem som helst forandre på det. Kanskje må du sende et objekt mellom to av dine klasser via et tredjepart objekt og du vil forsikre deg om at objektet kommer frem uendret. Kanskje du ønsker å bruke et objekt som en nøkkel i en hashtabell og du trenger å være trygg på at ingen endrer på objektet mens det er i bruk. Kanskje noe korrupterer et av objektene dine og du ønsker at Ruby skal heve et unntak så snart endringen tar sted.

Ruby tilbyr en veldig enkel mekanisme for å hjelpe til med dette. Et hvert objekt kan bli frosset ved å kalle Object#freeze . Et frosset objekt kan ikke endres: du kan ikke forandre instansvariablene (direkte eller indirekte), du kan ikke legge til singletonmetoder til det og hvis det er en klasse eller modul, kan du ikke legge til, slette eller endre dens metoder. Når et objekt først er frosset, forblir det frosset: det er ikke noen Object#thaw -metode. Du kan sjekke om et objekt er frosset ved hjelp av Object#frozen? .

Hva skjer når man kopierer et frosset objekt? Det er avhengig av metoden du bruker. Dersom du kaller objektets clone-metode, blir hele objektet tilstand (inklusive om objektet er frosset eller ikke) kopiert til det nye objektet. På den andre side, dup pleier typisk kun å kopiere objektets innhold---den nye kopien vil ikke arve den frosne tilstanden.

str1 = "hello"
str1.freeze » "hello"
str1.frozen? » true
str2 = str1.clone
str2.frozen? » true
str3 = str1.dup
str3.frozen? » false

Selv om frysing av objekter til å begynne med kan virke som en god ide, bør du kanskje vente til du kommer over et faktisk behov. Frysing er en av de ideene som virker helt essensielle på papiret men ikke er mye i praktisk bruk.

( In progress translation to Norwegian by NorwayRUG. $Revision: 1.11 $ )
$Log: classes.xml,v $
Revision 1.11  2003/07/31 13:22:22  kent
Lenker inn figurene.

Revision 1.10  2002/12/02 10:51:34  kent
Første kladd ferdig for "Klasser og objekter".

Revision 1.9  2002/12/01 17:01:29  kent
Frem til "Class Names are Constants"

Revision 1.8  2002/11/30 22:38:50  kent
Frem til "Mixin modules".

Revision 1.7  2002/10/21 18:54:10  kent
Frem til Object-Specific Classes

Revision 1.6  2002/10/20 21:29:32  kent
Kopierer inn LaTeX kildekode, da en bit mangler... Har sendt e-post til Dave og Andy.

Revision 1.5  2002/10/20 20:18:22  kent
Fikse noen figurer og ymse tekniske feil.

Revision 1.4  2002/10/20 20:08:51  kent
Nettopp begynt. Frem til "Your Basic, Everyday Object".


Forrige < Innhold ^
Neste >

Extracted from the book "Programming Ruby - The Pragmatic Programmer's Guide".
Translation to norwegian by Norway Ruby User Group.
Copyright for the english original authored by David Thomas and Andrew Hunt:
Copyright © 2001 Addison Wesley Longman, Inc.
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at
http://www.opencontent.org/openpub/).

(Please note that the license for the original has changed from the above. The above is the license of the original version that was used as a foundation for the translation efforts.)

Copyright for the norwegian translation:
Copyright © 2002 Norway Ruby User Group.
This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, v1.0 or later (the latest version is presently available at
http://www.opencontent.org/openpub/).
Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
Distribution of the work or derivative of the work in any standard (paper) book form is prohibited unless prior permission is obtained from the copyright holder.