Продолжим исследования Lotus Script, байт-кода и виртуальной машины.
Изменение состава членов класса и последующая перекомпиляция
В
этой теме я обещал объяснить, почему требуется перекомпиляция зависимых библиотек при изменении состава членов класса.
Рассмотрим пример.
Код:
'Library LibA
Public Class ClassA
Private a As Integer
Private b As Integer
...
End Class
'Library LibB
Use "LibA"
'где-нибудь в коде
Set a = New ClassA()
При компиляции библиотеки LibA в секцию определений помещается описание класса ClassA. Структура, описывающая класс, имеет, помимо всего прочего, поле, содержащее размер экземпляра класса в байтах.
При компиляции библиотеки LibB в ее байт-код также помещается описание класса ClassA. Теперь, если изменить код в библиотеке LibA на такой:
Код:
Public Class ClassA
Private a As Integer
Private b As Integer
Private c As Integer
Private d As Integer
...
End Class
, то получится очень интересная ситуация. В структуре описания класса ClassA в библиотеке LibA поле размера экземпляра содержит значение 8 (4 двухбайтных целых), а в библиотеке LibB - значение 4. Тут то мы и получаем заветное окно
Код:
---------------------------
IBM Lotus Notes
---------------------------
Type mismatch on external name: CLASSA
---------------------------
ОК
---------------------------
Но это еще не все. Перекомпилируем библиотеку LibB. Ошибки нет, все хорошо. Теперь еще немного изменим класс ClassA:
Код:
Public Class ClassA
Public a As Integer
Public b As Integer
Private c As Integer
Private d As Integer
...
End Class
Как ни странно, такое достаточно серьезное изменение интерфейса класса ClassA не приводит к необходимости перекомпиляции библиотеки LibB. Более того, даже такой код:
Код:
Public Class ClassA
Public a As Integer
Private c As Integer
Private d As Integer
Public e As Integer
...
End Class
не требует перекомпиляции библиотеки LibB, потому что размер объекта не изменился.
Что здесь меня удивляет. Вслед за описанием класса в байт-коде размещается описание всех его членов. Описание члена класса содержит, в том числе, смещение содержимого переменной в области памяти, отведенной объекту. В примере выше класс ClassA занимает в памяти 8 байт, первые два байта отведены переменной a (смещение 0), последующие - переменной c (смещение 2), переменной d (смещение 4) и переменной e (смещение 6).
Некоторые инструкции обращаются к переменной (и ее значению) не по адресу ее описания (косвенно), а по ее смещению в объекте (непосредственно). Так вот, можно ли изменить поведение кода в библиотеке LibB, изменив лишь порядок публичных членов класса ClassA? Этот вопрос требует дополнительного исследования.
----------------
И еще два вопроса из
link removed
Про оператор With.
ToxaRat сказал(а):
Код, использующий With:
Код:
Dim doc As NotesDocument
With doc
.replaceItemValue "item1", "1"
.replaceItemValue "item2", "2"
End With
эквивалентен следующему:
Код:
Dim doc As NotesDocument
Dim tmpRef As NotesDocument
Set tmpRef = doc
tmpRef.replaceItemValue "item1", "1"
tmpRef.replaceItemValue "item2", "2"
Set tmpRef = Nothing
, а не такому, как казалось бы:
Код:
Dim doc As NotesDocument
doc.replaceItemValue "item1", "1"
doc.replaceItemValue "item2", "2"
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Подтверждение:</div></div><div class="sp-body"><div class="sp-content">
Код:
Public Sub doSomething(doc As NotesDocument)
doc.ReplaceItemValue "item1", "1"
doc.ReplaceItemValue "item2", "2"
With doc
.ReplaceItemValue "item1", "1"
.ReplaseItemValue "item2", "2"
End With
End Sub
Код:
Public Sub DOSOMETHING(DOC As NOTESDOCUMENT)
Dim WithVariable0520 As NOTESDOCUMENT
line # 20
rvalue_object DOC
push_lsx_routine REPLACEITEMVALUE
push_str_const {item1}
push_str_const {1}
call_routine
pop
line # 21
rvalue_object DOC
push_lsx_routine REPLACEITEMVALUE
push_str_const {item2}
push_str_const {2}
call_routine
pop
line # 23
lvalue_l WithVariable0520
rvalue_p DOC
Set
line # 24
rvalue_object WithVariable0520
push_lsx_routine REPLACEITEMVALUE
push_str_const {item1}
push_str_const {1}
call_routine
pop
line # 25
rvalue_object WithVariable0520
push notes sub REPLASEITEMVALUE
push_str_const {item2}
push_str_const {2}
Call notes sub
lvalue_l WithVariable0520
push_Nothing
Set
line # 27
end_routine
End Sub
Косвенно об этом говорится в справке:
LotusScript does not support entering a With statement using GoTo.
То есть, такой трюк не получится:
Код:
Dim doc As NotesDocument
...
Goto label1
...
With doc
.replaceItemValue "item1", "1"
label1:
.replaceItemValue "item2", "2"
End With
Потому что в этом случае временная ссылка на doc не будет проинициализирована.
----------------
Про то, что лучше (быстрее): вызов конструктора или метод создания
nvy сказал(а):
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Показываю байт-код.</div></div><div class="sp-body"><div class="sp-content">
Код:
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As New NotesDocument(db)
Dim rti As New NotesRichTextItem(doc, "Body")
End Sub
Private Sub INITIALIZE()
Dim S As NOTESSESSION
Dim DB As NOTESDATABASE
Dim DOC As NOTESDOCUMENT
Dim RTI As NOTESRICHTEXTITEM
line # 12
lvalue_l S
push_lsx_constructor NOTESSESSION
call_new
Set
line # 14
lvalue_l DB
rvalue_object S
push_lsx_property CURRENTDATABASE
call_routine
Set
line # 15
lvalue_l DOC
push_lsx_constructor NOTESDOCUMENT
lvalue_l DB
call_new
Set
line # 16
lvalue_l RTI
push_lsx_constructor NOTESRICHTEXTITEM
rvalue_l DOC
push_str_const {Body}
call_new
Set
line # 17
end_routine
End Sub
Код:
Sub Initialize
Dim s As NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim rti As NotesRichTextItem
Set s = New NotesSession
Set db = s.CurrentDatabase
Set doc = New NotesDocument(db)
Set rti = New NotesRichTextItem(doc, "Body")
End Sub
Private Sub INITIALIZE()
Dim S As NOTESSESSION
Dim DB As NOTESDATABASE
Dim DOC As NOTESDOCUMENT
Dim RTI As NOTESRICHTEXTITEM
line # 16
lvalue_l S
push_lsx_constructor NOTESSESSION
call_new
Set
line # 17
lvalue_l DB
rvalue_object S
push_lsx_property CURRENTDATABASE
call_routine
Set
line # 18
lvalue_l DOC
push_lsx_constructor NOTESDOCUMENT
lvalue_l DB
call_new
Set
line # 19
lvalue_l RTI
push_lsx_constructor NOTESRICHTEXTITEM
rvalue_l DOC
push_str_const {Body}
call_new
Set
line # 20
end_routine
End Sub
Код:
Sub Initialize
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As NotesDocument
Set doc = db.CreateDocument
Dim rti As NotesRichTextItem 'Dim rti As New NotesRichTextItem(doc, "Body")
Set rti = doc.CreateRichTextItem("Body")
End Sub
Private Sub INITIALIZE()
Dim S As NOTESSESSION
Dim DB As NOTESDATABASE
Dim DOC As NOTESDOCUMENT
Dim RTI As NOTESRICHTEXTITEM
line # 12
lvalue_l S
push_lsx_constructor NOTESSESSION
call_new
Set
line # 14
lvalue_l DB
rvalue_object S
push_lsx_property CURRENTDATABASE
call_routine
Set
line # 16
lvalue_l DOC
rvalue_object DB
push_lsx_routine CREATEDOCUMENT
call_routine
Set
line # 18
lvalue_l RTI
rvalue_object DOC
push_lsx_routine CREATERICHTEXTITEM
push_str_const {Body}
call_routine
Set
line # 19
end_routine
End Sub
Чем может помочь этот листинг - мне не понятно. Во всех случаях вызываются функции из внешней библиотеки %lsxbe (nlsxbe.dll в случае Windows). А вот в них ковыряться ну совсем никакого желания нет. Желающие - welcome. Может быть, поможет
Ссылка скрыта от гостей
.