Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
In sommige gevallen is het gewoon gemakkelijker/beter om een delegate te gebruiken ipv interfaces en omgekeerd.
En wat is er mis met properties. Als je een goed OO-model hebt uitgedacht, dan ga je de access-modifiers van uw members niet moeten veranderen. Dat doe je imho enkel en alleen maar als je direct begint te programmeren zonder dat je er eerst een goede class-structuur voor gemaakt hebt.
Properties zijn gewoon gemakkelijk en leesbaar. Java heeft geen properties maar lost dit op door set en get-functies en wat is het wezenlijke verschil?
Als je goede naming-conventions toepast, dan hoef je niet te verwarren tussen properties en member-variables. Ik vind dit nogal ver gezocht.
Waar hij wel een punt heeft, is het verschil in type tussen structs en classes. Hier kan misschien wel wat verwarring ontstaan omdat een struct een value-type is, en een class is een reference-type.
https://fgheysels.github.io/
- TheOneLLama
- Registratie: Oktober 2000
- Laatst online: 20-01-2022
A llama like no llama before
Deze dingen zijn echter een keuze en onderdeel van de taal.. of je ze gebruikt of niet is nog altijd je eigen beslissing maar iemand dit compleet af te raden vind ik wel ver gaan..
Ook zou je structs alleen maar moeten gebruiken als er hogere performance nodig is (en dus niet al zodra je er hogere perfomance mee kan halen).
Als User-defined implicit conversions is wat ik denk wat het is in C# (ben nog niet erg bekend met C#) dan lijkt het me dat je code daar inderdaad niet veel duidelijker op wordt.
Zoals al blijkt uit m'n posting ben ik niet echt bepaald een expert in C#
Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com
Tja, da's ook een beetje een kwestie van persoonlijke voorkeur. Ik vind het event-model van Delphi en C# (dus met die function-pointers cq delegates) wel prettig werken en veel duidelijker. Maar da's een kwestie van smaak.Op zaterdag 01 juni 2002 14:29 schreef TheOneLLama het volgende:
Ik ben het er wel mee eens dat delegates, event pointers en properties onnodig zijn.. Als je kijkt naar 2 voorbeelden van GUI omgevingen van C++ (Qt) en JAVA (Swing) dan zie je dat het ook zonder deze dingen goed kan (op taal-niveau). Als je dat vergelijkt met Delphi (wel event pointers en properties op language niveau) geef ik voorkeur aan 1 van de anderen..
https://fgheysels.github.io/
Mwah, hij vermeldt op z'n website veel C# bronnen en maakt ook een vergelijking tov van C++. Het is wel wat makkelijk om iedereen die kritiek heeft op een constructie in C# gelijk maar af te doen als pro-Java en anti-C#. Je argumentatie van gaat dan snel richting de subjectiviteit van de schrijver, wat een inhoudelijke discussie in de weg staat.whoami: Volgens mij is de auteur een Java-programmeur die gewoon iedereen ervan wil overtuigen dat Java beter is dan C# en dat alle features die C# heeft en Java niet toch maar useless en gevaarlijk zijn.
Nou ja, ik mis hier toch wel een argumentatie. We hebben het al in een eerder topic gehad over de relatie tussen interfaces en delegates waarbij iedereen me wat wazig aankeek. Ik denk toch echt dat je beide concepten kunt en moet vergelijken met elkaar.In sommige gevallen is het gewoon gemakkelijker/beter om een delegate te gebruiken ipv interfaces en omgekeerd.
Het enige voordeel wat ik zie van delegates ten opzichte van interfaces is dat je via delegates functionaliteit kunt gebruiken die de klasse niet heeft aangegeven via een interface. Bij interfaces kan je de functionaliteit van de interface alleen toepassen als de klasse die interface ook daadwerkelijk geimplementeerd heeft. Overigens kan je daarvoor ook wel at-runtime wrappers genereren, maar dat is in ieder geval ranziger dan delegates
Het verschil wordt heel goed geillustreerd in het stukje: bij het aanroepen van een property in Java zie je duidelijk dat er een methode wordt aangeroepen. Deze methode kan dure operaties uitvoeren zoals daar ook is geillustreerd. Bij een property in C# laat alleen de naming convention zien of er in werkelijkheid een methode wordt aangeroepen of dat het een directe assignment/get is. Nu is het inderdaad zo dat je die naming convetion ook gewoon goed moet aanhouden, dus in feite moet je dan bekijken of de naming conventie duidelijk is dat een methode aanroep.En wat is er mis met properties. Als je een goed OO-model hebt uitgedacht, dan ga je de access-modifiers van uw members niet moeten veranderen. Dat doe je imho enkel en alleen maar als je direct begint te programmeren zonder dat je er eerst een goede class-structuur voor gemaakt hebt.
Properties zijn gewoon gemakkelijk en leesbaar. Java heeft geen properties maar lost dit op door set en get-functies en wat is het wezenlijke verschil?
Overigens vind ik dit ook een wat minder punt, met de delegates kan ik het meer eens zijn.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
C# kent wel degelijk implicit conversions, maar die moeten uiteraard wel door de programmeur gedefinieerd zijn in 1 van de betrokken klassen.whoami: Ik vraag me eigenlijk af of implicit conversions eigenlijk toegestaan zijn in C#. C# is toch type-safe, dus verwacht ik dat enkel maar expliciete conversions mogen?
Het heeft niet zoveel te maken met type-safety. De impliciete conversies zijn gewoon verborgen methode-aanroepen die een conversie uitvoeren van het 1 type naar het andere. Deze methode moet je zelf implementeren, maar bij het gebruik van de impliciete conversie hoef je deze methode dus niet aan te roepen.
C# gaat uiteraard niet op 1 of andere magische manier een conversie proberen uit te voeren
Type-safety is trouwens sowieso een term waarmee je uit moet kijken in deze context. C# zal namelijk best garanderen dat er nooit een illegale operatie kan worden uitgevoerd op een item (dat is type-safety), maar kan dit at compile time niet controleren: er kan best een incorrecte cast uitgevoerd worden.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
Ja, idd. Misschien een beetje 'te kort door de bocht' van mij. (Of hoe zeggen jullie Nederlanders datOp zaterdag 01 juni 2002 14:42 schreef mbravenboer het volgende:
Mwah, hij vermeldt op z'n website veel C# bronnen en maakt ook een vergelijking tov van C++. Het is wel wat makkelijk om iedereen die kritiek heeft op een constructie in C# gelijk maar af te doen als pro-Java en anti-C#. Je argumentatie van gaat dan snel richting de subjectiviteit van de schrijver, wat een inhoudelijke discussie in de weg staat.
Tja, ik heb hier ooit eens in een topic een post geplaatst met een voorbeeld van een geval waarin ik delegates toepas. Ik zal het topic eens gaan opzoeken.Nou ja, ik mis hier toch wel een argumentatie. We hebben het al in een eerder topic gehad over de relatie tussen interfaces en delegates waarbij iedereen me wat wazig aankeek. Ik denk toch echt dat je beide concepten kunt en moet vergelijken met elkaar.
Het enige voordeel wat ik zie van delegates ten opzichte van interfaces is dat je via delegates functionaliteit kunt gebruiken die de klasse niet heeft aangegeven via een interface. Bij interfaces kan je de functionaliteit van de interface alleen toepassen als de klasse die interface ook daadwerkelijk geimplementeerd heeft. Overigens kan je daarvoor ook wel at-runtime wrappers genereren, maar dat is in ieder geval ranziger dan delegates.
Edit: hier issie http://gathering.tweakers.net/forum/list_message/13353671#13353671
Ik weet niet hoe je iets dergelijks even makkelijk en leesbaar kunt oplossen dmv interfaces.
Misschien is het op 't eerste zicht idd niet duidelijk of de property of de member rechtstreeks aangesproken wordt, maar we zijn er het alvast over eens dat door consequente naming-conventions toe te passen dit probleem toch uit de weg kan gegaan worden. Ik vind in sommige gevallen properties gewoon veel duidelijker dan getters en setters.Het verschil wordt heel goed geillustreerd in het stukje: bij het aanroepen van een property in Java zie je duidelijk dat er een methode wordt aangeroepen. Deze methode kan dure operaties uitvoeren zoals daar ook is geillustreerd. Bij een property in C# laat alleen de naming convention zien of er in werkelijkheid een methode wordt aangeroepen of dat het een directe assignment/get is. Nu is het inderdaad zo dat je die naming convetion ook gewoon goed moet aanhouden, dus in feite moet je dan bekijken of de naming conventie duidelijk is dat een methode aanroep.
Overigens vind ik dit ook een wat minder punt, met de delegates kan ik het meer eens zijn.
Bv:
1
| MyObject.Counter++; |
tov:
1
| MyObject.SetCounter(MyObject.GetCounter()++); |
https://fgheysels.github.io/
Ik vind dit toch wel een hele rare gedachtenkronkel die hij hier maakt. In het voorbeeld verwart hij missiles met employees en geeft de taal de schuldOp zaterdag 01 juni 2002 13:25 schreef mbravenboer het volgende:
Ik kwam dit stuk tegen:
* Prefer interfaces over delegates
Ik vind delegates niet het mooiste onderdeel van de taal, maar het is op functie niveau wel type-safe. De vrijheid om elke functie toe te wijzen met dezelfde specificaties kan natuurlijk ook in je voordeel werken.
Stel je hebt een heel plausibele delegate voor een 'void DoeIets()'. Je kan dan dit bv koppelen aan het afsluiten van je programma, het aanroepen van een 3rd-party webservice. Plus dat je de binding later gemakkelijk kan veranderen. Zouden al deze onderdelen een bepaalde interface moeten implementeren?
Een interface geeft aan welke set operaties een object kan uitvoeren. Een delegate zie ik meer als de lijm om verschillende componenten met elkaar te laten praten.
Onzin. Moet ik dan voor elke private member getters/setters gaan schrijven? Dit komt precies op hetzelfde neer.* Discourage use of properties
Zijn 1e voorbeeld gaat niet op omdat een goede C# programmeur standaard al begint met properties. Hierdoor kan je in een later stadium nooit client-code breken.
Het is natuurlijk logisch dat de functie van een property niet mag veranderen.
Het hele efficientie verhaal vind ik een beetje dubieus. Het lijkt me dat de compiler een property zoals deze:
1
2
3
4
| public int Getal
{
get { return getal; }
... |
gewoon wegcompileert, en dat je dus direct getal aanspreekt.
Impliciete conversies komen niet zo vaak voor omdat de gebrukte classes vaak te divers zijn. Het heeft totaal geen betekenis om een class Car naar een class House te casten bijvoorbeeld.* Do not use user-defined implicit conversions
Bij het casten van class<->class is het zeker mooier om dit via een constructor te doen.
Een veel sterker argument (wat hier niet genoemd wordt) om geen impliciete conversies te gebruiken is dat de compiler via allerlei wegen zal proberen uit te vinden die cast mogelijk te maken. Stel je hebt een impliciete int cast. Deze code:
float a = MijnClass;
Zal dan misschien niet opleveren wat je verwacht omdat bij de conversie naar int het getal wordt afgerond.
Structs moet je gewoon benaderen als primitieven. Microsoft gebruikt voor structs voor vrij primitieve objecten (Points, Size, etc). Dit gaat helemaal niet in tegen het 'principle of uniformity' omdat programmeurs die objecten instinctief gaat behandelen als value-types.* Do not use structs
Stel je voor dat je een paint functie hebt waarbij de locatie wordt aangegeven van je control. Ik denk dat 9 van de 10 programmeurs niet
Point p = new Point(pointFromCaller)
zal gebruiken aan het begin van hun functie wanneer ze de locatie gaan veranderen.
Dat zal een beetje moeilijk gaan* Do not use boxing and unboxing
Nou de argumenten hier overlappen een beetje met die van het structs probleem. Boxing/unboxing is bedoelt om primitieves te kunnen behandelen als een object. Op deze manier kan je dus zowel integers als objecten in een ArrayList proppen.
Hij gebruikt in het voorbeeld de 'is' operator, waarom niet de equality == operator ? Die doet namelijk precies wat hij wil, de waardes vergelijken.
References vergelijken bij primitieven is vrij onzinnig omdat die meestal niet gelijk zijn en de waardes zelf vergelijken gaat ook nog eens snel.
dit is lang he
Je mag het ook wel op z'n Belgisch zeggen hoor, kunnen wij ook eens lachenwhoami: Of hoe zeggen jullie Nederlanders dat
Ok. Ik heb zelf overigens in C# ook wel delegates gebruikt omdat je er sowieso niet omheen kan als je met de .NET libraries werkt, maar in m'n eigen werk geef ik toch vaak de voorkeur aan interface die duidelijke de capaciteit van een klasse aangeven.Tja, ik heb hier ooit eens in een topic een post geplaatst met een voorbeeld van een geval waarin ik delegates toepas. Ik zal het topic eens gaan opzoeken.
Wat dacht je van:Bv:
code:
1 MyObject.Counter++;
tov:
code:
1 MyObject.SetCounter(MyObject.GetCounter()++);
MyObject.IncreaseCounter();
Overigens is het inderdaad wel zo dat je in get-set situaties (zoals hier het geval is) duidelijk voordeel hebt van properties qua compactheid als je 1 van de compacte assignments kunt gebruiken.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
Het gaat in zijn verhaal om het aangeven van capaciteiten. Als je van interfaces gebruik maakt geeft een klasse aan dat hij bepaalde funcionaliteit bezit.Orphix: Ik vind dit toch wel een hele rare gedachtenkronkel die hij hier maakt. In het voorbeeld verwart hij missiles met employees en geeft de taal de schuld
Met delegates is dit niet mogelijk om dat slechts het signatuur van de methode gelijk moet zijn aan de delegate declaratie. Er is dan echter geen enkele garantie dat die methode ook daadwerkelijk semantisch gezien doet waar de delegate voor gedefinieerd is.
Bij interface heeft de schrijver van de klasse hier controle over: hij geeft de capaciteit aan.
Mwah, set operaties vind ik wel wat beperkt voor interfaces. ook interface kan je gebruiken om componenten met elkaar te laten babbelen. Denk maar eens aan de Runnable, Comparator, Comparable, SAX ContentHandler, ErrorHandler enzovoorts.Een interface geeft aan welke set operaties een object kan uitvoeren. Een delegate zie ik meer als de lijm om verschillende componenten met elkaar te laten praten.
Nee: als je getters en setters gebruikt moet je de getters en setters ook echt aanroepen. Je ziet dus wat er gebeurt door middel van de methode aanroep. Bij properties zie je wat er gebeurt door de naming convention.Onzin. Moet ik dan voor elke private member getters/setters gaan schrijven? Dit komt precies op hetzelfde neer.
Het gaat niet om simpele gets en sets (die worden inderdaad ge-inlined, net als simpele gets en sets in Java).gewoon wegcompileert, en dat je dus direct getal aanspreekt.
Het gaat in zijn performance inzicht argument over extra operaties die worden uitgevoerd door een getter of setter. Een get of set hoeft namelijk niet slechts een waarde op te leveren of te setten, maar kan juist ook veel meer doen.
Ik zeg trouwens niet dat ik het overal mee eens ben, wel vind ik dat je goed rekening moet houden met de punten die genoemd worden. Je moet dus aardig wat afweten van de betekenis van de diverse concepten voordat je er op een veilige en vertrouwde manier mee om kunt gaan.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
Ik zei het op z'n Nederlands omdat ik niet zo direct een equivalente Belgische uitspraak weet...Op zaterdag 01 juni 2002 15:00 schreef mbravenboer het volgende:
Je mag het ook wel op z'n Belgisch zeggen hoor, kunnen wij ook eens lachen.
Heb het ondertussen gevonden.Ok. Ik heb zelf overigens in C# ook wel delegates gebruikt omdat je er sowieso niet omheen kan als je met de .NET libraries werkt, maar in m'n eigen werk geef ik toch vaak de voorkeur aan interface die duidelijke de capaciteit van een klasse aangeven.
Ja, idd. Maar ik wou gewoon maar een punt duidelijk maken. Stom voorbeeld van me misschien.Wat dacht je van:
code:
1 MyObject.IncreaseCounter();
.
https://fgheysels.github.io/
Verwijderd
Hij vergelijkt
Maar ervan uitgaande dat Sum gedefinieerd is als:public void Calc(int[] foo)
{
Sum = 0;
for (int i = 0; i < foo.Length; i++)
Sum += foo[i];
}
////////////////////////////////////
{
Sum = 0;
for (int i = 0; i < foo.Length; i++)
SetSum(GetSum() + foo[i]);
}
////////////////////////////////////
{
int temp = 0;
for (int i = 0; i < foo.Length; i++)
temp += foo[i];
SetSum(temp);
}
1
2
3
4
5
6
7
8
9
10
11
| public int Sum
{
get
{
return _sum;
}
set
{
_sum = value;
}
} |
Dan zie ik toch echt niet wat er zo ineffecient aan is. In het voorbeeld dat de auteur aandraagt wordt immers ook steeds een variabele opgevraagd en geset.
Bovendien maakt hij de code wel logisch bij de Get/Set manier en niet bij de properties manier...
Ik vind Properties juist een van de allergrootste voordelen van C# t.o.v. Java
/me vindt z'n eigen coding guidelines veel mooier, beter en duidelijker
Ik heb toch liever het blackbox-idee. De klasse roept de delegate aan wanneer dat nodig is en wat de client-programmeur ermee doet is zijn taak. Als hij dan missiles wil sturen, so be it.Op zaterdag 01 juni 2002 15:11 schreef mbravenboer het volgende:
Het gaat in zijn verhaal om het aangeven van capaciteiten. Als je van interfaces gebruik maakt geeft een klasse aan dat hij bepaalde funcionaliteit bezit.
Met delegates is dit niet mogelijk om dat slechts het signatuur van de methode gelijk moet zijn aan de delegate declaratie. Er is dan echter geen enkele garantie dat die methode ook daadwerkelijk semantisch gezien doet waar de delegate voor gedefinieerd is.
Aan een delegate kun je ook meerdere functies hangen, hoe wil je dit oplossen met interfaces?
Ik heb alleen nog maar in vs.net gewerkt en dan zie je tijdens het typen al duidelijk wat een property is en wat niet, ook in de documentatie staat dit.Nee: als je getters en setters gebruikt moet je de getters en setters ook echt aanroepen. Je ziet dus wat er gebeurt door middel van de methode aanroep. Bij properties zie je wat er gebeurt door de naming convention.
...
Maar ook al weet je het niet of het een property is of niet, wat maakt het uit?
Ik ben het met je eens dat kostbare operaties een aparte methode moeten krijgen. Maar stel dat een property zoveel doet dat het traag wordt. Dan kan je alsnog besluiten om eenmaal die property op te halen en daar verder mee te werken.
- TheOneLLama
- Registratie: Oktober 2000
- Laatst online: 20-01-2022
A llama like no llama before
Precies.. en in C# en zeker in Delphi wordt je toch vooral richting in gedreven.. Maar om nou te negeren dat het in die talen werkt en te zeggen: dat moet je dus niet gebruiken is een stapje te verOp zaterdag 01 juni 2002 14:37 schreef whoami het volgende:
Tja, da's ook een beetje een kwestie van persoonlijke voorkeur. Ik vind het event-model van Delphi en C# (dus met die function-pointers cq delegates) wel prettig werken en veel duidelijker. Maar da's een kwestie van smaak.
Dan lijkt mij gewoon zelf een method maken en die aanroepen mij duidelijker.. (desnoods op basis van een interface).Op zaterdag 01 juni 2002 14:52 schreef mbravenboer het volgende:
[..]
C# kent wel degelijk implicit conversions, maar die moeten uiteraard wel door de programmeur gedefinieerd zijn in 1 van de betrokken klassen.
Het heeft niet zoveel te maken met type-safety. De impliciete conversies zijn gewoon verborgen methode-aanroepen die een conversie uitvoeren van het 1 type naar het andere. Deze methode moet je zelf implementeren, maar bij het gebruik van de impliciete conversie hoef je deze methode dus niet aan te roepen.
Opera OpenOffice.org Jabber Psi jabber://llama@mordax.com
Mwah, ik ervaar deze reacties niet als verliezen hoorGordijnstok: omg mbravenboer on the looseWelcome back..
Wat ik wel jammer vind is dat er allerlei suiker en minder relevant materiaal aan C# is toegevoegd ten opzichte van Java, terwijl er veel meer echt innovatieve ideeen in opgenomen hadden kunnen worden zoals bijvoorbeeld in Nice. Met name het aangeven dat een variabele null kan zijn of dat een methode null kan opleveren vind ik erg fraai en lost een echt probleem op wat er is in de taal Java.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
Het punt is juist dat hij ze daar niet wilde sturenOrphix: Ik heb toch liever het blackbox-idee. De klasse roept de delegate aan wanneer dat nodig is en wat de client-programmeur ermee doet is zijn taak. Als hij dan missiles wil sturen, so be it.
Als je dat nodig hebt kan je een implementatie van de interface maken die twee andere implementaties van de interface combineert. Voordeel daarvan is dat je ook nog extra gedrag kunt toevoegen.Aan een delegate kun je ook meerdere functies hangen, hoe wil je dit oplossen met interfaces?
Voorbeeld:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public interface Filter<T> {
public boolean accept(T item);
}
public class OrFilter<T> implements Filter<T> {
private Filter<T> _first;
private Filter<T> _second;
public OrFilter(Filter<T> first, Filter<T> second) {
super();
_first = first;
_second = second;
}
public boolean accept(T item) {
return _first.accept(item) || _second.accept(item);
}
} |
Als jij een Runnable wilt die meerdere Runnables kan runnen, implementeer je een Runnable die dat doet
Helaas is dat vanwege de verbositeit van deze categorie talen vrij veel werk: het is juist erg gebruikelijk om op deze manier te werken in compactere, declaratieve talen.
Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment
by the way Delegates zijn niets meer dan "the good old" functie pointers alleen dan op zijn type safes
Het verhaal dat je juist geen properties moet gebruiken zegt voor mij al genoeg
Dat verhaal over structs is helmaal om te brullen. Voor mensen die dan echt willen weten hoe het zit. Mensen die echt van een ervaren programmeur willen horen wat nou net de tradeoffs zijnvan C# tov Java/C++. Mensen die een snelle efficiente insight willen hebben:
Lees, "C# Unleashed by Joseph Mayo"
Alle info op mtb die FAQ is wel zo extreem kort door de bocht. Duik de MSDN eens een keer in, MS geeft deze keer heel duidelijk aan waarom dingen wel of niet volgens een bepaalde methodiek aan te pakken. MS geeft ook duidelijk aan dat de taal niet heilig makend is, maar het Framework en de gedachtengang achter .NET voor de programmeurt.
mtb het delegate/event model vs the good old IObservable/IObserver artikel...erg leerzaam! Daarin wordt duidelijk uiteengezet waarom geen Interfaces en wel
MS observerpattern
Off-Topic.Op zaterdag 01 juni 2002 15:56 schreef mbravenboer het volgende:
Mwah, ik ervaar deze reacties niet als verliezen hoor.
Ik denk niet dat er bedoeld werd dat je aan het verliezen waart.
To be on the loose:aan de rol, aan de zwabber zijn.
https://fgheysels.github.io/
Ter vergelijking, in C++ zijn function pointers wel really typesafe, en desgewenst ook OO (pointer to member).Q: What do delegates buy you?
A: Delegates enable scenarios that some other languages have addressed with function pointers. However, unlike function pointers, delegates are object-oriented and type-safe.
Q: Are delegates really type-safe?
Not really. A delegate instance does not know or care about the classes of the methods it encapsulates; all that matters is that those methods be compatible with the delegate's type.
tweede voorbeeld van site:
Let op het verschil tussen a.x en b.x... in C++ the syntax for using a class/struct reference is very different from the syntax for using a class/struct value.
1
2
3
4
5
| #include "myClass.h" myClass a; myClass& b = a; a.x=1; b.x=2; |
Wereld van verschil, toch ?
Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein