Lotus Script: взгляд изнутри

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
Мои эксперименты показывают, что байт-код в первом случае получается короче. Аналогичная картина для New NotesRichTextItem против doc.CreateRichTextItem. Так что использование New выгоднее. Правда он в COM не поддерживается, но для ЛС это не принципиально.
а не могли бы еще проверить на скорость
скажем милион раз тот код и этот и какая разница в секундах?

Почему спрашиваю, так как короткий код еще не означает быстрый.
 
N

nvyush

а не могли бы еще проверить на скорость
скажем милион раз тот код и этот и какая разница в секундах?

Почему спрашиваю, так как короткий код еще не означает быстрый.
Согласен с последним тезисом, но кмк это не тот случай. Насколько я понимаю, в варианте с New непосредственно вызывается конструктор класса, в варианте с db.CreateDocument сперва вызывается метод CreateDocument, который в свою очередь вызывает конструктор. Если бы Yakov имел время/возможность/желание проанализировать данные варианты своей утилитой и показать байт-код, то все вопросы отпали бы сами собой. Писать тесты на скорость у меня, к сожалению, сейчас нет времени.
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
nvy
Писать тесты на скорость у меня, к сожалению, сейчас нет времени.
а может проверите?, и если будет разница, назову эту проверку в вашу честь :)
 
Y

Yakov

Продолжим исследования 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. Может быть, поможет .
 
V

vital

<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">И почему Yakov не в лотус тим?=)
 
N

nvyush

nvy

а может проверите?, и если будет разница, назову эту проверку в вашу честь ;)
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Test Agent Code</div></div><div class="sp-body"><div class="sp-content">
Код:
Option Public
Option Declare
Sub Initialize
Dim c1 As Long
Dim c2 As Long	
Dim t1 As Variant
Dim i1 As Long
Dim i2 As Long
Dim sumNew As Double
Dim sumCre As Double
sumNew = 0
sumCre = 0
c1 = 1000
c2 = 1000
For i2 = 1 To c2
t1 = Now
For i1 = 1 To c1
callCre
Next i1
sumCre = sumCre + (Cdbl(Now) - Cdbl(t1))
t1 = Now
For i1 = 1 To c1
callNew
Next i1
sumNew = sumNew + (Cdbl(Now) - Cdbl(t1))
Next i2
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As NotesDocument
Set doc = New NotesDocument(db)
Call doc.ReplaceItemValue("Form", "Memo")
Call doc.ReplaceItemValue("Body", "C:" + Cstr(sumCre) + Chr(10) + "N:" + Cstr(sumNew))
Call doc.Send(False, "CN=Your Name/OU=Your Unit/O=Your Organization")
End Sub
Sub callCre()
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As NotesDocument
Set doc = db.CreateDocument	
End Sub
Sub callNew()
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As NotesDocument
Set doc = New NotesDocument(db)
End Sub
Результат первого запуска:
C:2.01388890127419E-03 (00:02:54)
N:1.90972221025731E-03 (00:02:45)
Результат второго запуска:
C:1.93287037109258E-03 (00:02:47)
N:1.89814814802958E-03 (00:02:44)
Разница мизерная, но есть. Кто хочет, может продолжить эксперименты. Для перевода результатов во временные единицы можно использовать код вида Msgbox(Format(Cdat(2.01388890127419E-03),"hh:mm:ss"))

P.S. В мою честь называть ничего не надо.
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
че-то тема заглохла, неужто ни у кого нету идей?
я вот тут думаю что если кнопка весит больше 10К(откомпиленный код+исходник) то считаю, что необходми оставить в ней собаку, которая вызывает агент
как думаете с размером я угадал? :)
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
TIA
А почему бы не вынести код в библиотеку?
и тем самым кнопка еще будет тянуть на себя весь всей библиотеки, не это самый плохой вариант

а на каком потолке эту цифру увидел?
да, действительно, не поделился промежуточными данными

скажем пользователь открывает док с данными, которые весят 4К, итого чтобы данные как-то ложились в обьем 64К нужно чтобы оставшиеся 60К занимала форма с кнопками, допустим 30К это форма, итого осталось 30К, в любой достаточно сложной системе обычно около 3 мега кнопок: согласование, подписывание, ознакомление, каждой отдаём по 10К.

Так что с размером, угадал?
 
T

TIA

и тем самым кнопка еще будет тянуть на себя весь всей библиотеки, не это самый плохой вариант
Вариант не равноценный, но не без плюсов. При выносе кода в библиотеку есть возможность использовать уже полученные данные и "тяжелые" объекты, а не получать их заново внутри агентов. И это важнее нескольких килобайт дополнительного кода.
Но и эта проблема решается динамической подгрузкой библиотек через Execute. Т.е. подгрузка произойдёт только при нажатии кнопок. Кстати, в акциях такое поведение штатно.
Так что не будьте столь категоричны на счёт "самого плохого варианта".

скажем пользователь открывает док с данными, которые весят 4К, итого чтобы данные как-то ложились в обьем 64К нужно чтобы оставшиеся 60К
Бред. Срочно ищи супомухный сепаратор.
 
A

Akupaka

скажем пользователь открывает док с данными, которые весят 4К, итого чтобы данные как-то ложились в обьем 64К нужно чтобы оставшиеся 60К занимала форма с кнопками, допустим 30К это форма, итого осталось 30К, в любой достаточно сложной системе обычно около 3 мега кнопок: согласование, подписывание, ознакомление, каждой отдаём по 10К.
ты чего, в мэсэдос перепрограммировался на днях? :ya_lamo:
 
H

hosm

еще некоторые "особенности" лотус-скрипта, описанные и исследованные нашими форумчанами:
1) поиск по Search и стабы: https://codeby.net/threads/34673.html?vi...st&p=164019 из темы link removed
2) сага о вАриантах лист возвращающих - на память граблепроходцам :rolleyes: и т.д.:
link removed
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
прошу поправить меня или обьяснить, всё касательно того же эксперимента про вынос кода кнопок на агенты:

Если в подформе в глобалах обьявить использование библиотеки то при сохранении такой подформы её размер увеличивается в среднем на размер откомпиленой библиотеки, хм... может это и понятно НО -
Если обьявить также эту библиотеку в Экшинах этой же подформы то размер подформы увеличиваеться ЕЩЕ на столько же.
Да и похоже если создать еще один Экшен с опять одной и тойже библиотекой то опять идет увеличение на такой же размер.
Походу глобал подформы пересекается с экшенами только переменными, размер компиленого кода увеличивается независимо от того, что уже задекларирована ранее в глобалах.
Я использовал сложную библиотеку которая тянет еще десяток библиотек.
Возможно это глюк дизайнера, но обычно у меня к 6.5.6 небыло нареканий вообще.
Стоило же снести весь код экшенов в агенты которые запускаются по собаке @Command([ToolsRunMacro];"ХХХ") размер под формы удалось уменьшить сразу на треть(более чем на 100К за 3 экшена)
 
T

TIA

Я попробовал. В моих экспериментах нет такой зависимости от размера подключаемой библиотеки.
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
TIA
Я попробовал. В моих экспериментах нет такой зависимости от размера подключаемой библиотеки
размер библиотеки это эмпирическим путем вычислял, но согласны с тем что подключаемая библиотека каким-то образом увеличивает вес формы/подформы?
может это какой-то комбинированный глюк если глобал формы и экшены содержат одну библиотеку?
 
T

TIA

может это какой-то комбинированный глюк если глобал формы и экшены содержат одну библиотеку?
Новая пустая форма - 1,1кб
Добавил "'" (т.е. появился скрипт, содержащий только коммент) - 2кб.
Добавил Use в глобал - 2,1 кб
Добавил акцию с "'" - 5кб
Добавил Use в акции - 5,1кб
Добавил 2ю акцию с "'" - 7,7
Добавил Use во 2й акции - 7,8кб
Добавил ешё формульную акцию - 7,9кб

Т.е. основной рост размера от самого факта добавления скриптовой акции, от числа юзов и объёма библиотек в меньшей степени.

согласны с тем что подключаемая библиотека каким-то образом увеличивает вес формы/подформы?
Да. Но 100б - это копейки.
 

ToxaRat

Чёрный маг
Green Team
06.11.2007
3 332
42
BIT
0
Речь идёт о приросте в 0,1 кб при добавлении Use
а вы использовали просто юз или какуе-то процедуру оттуда, желательно не из прямой библиотеке а дочерней, вызываемой оттуда
так как у меня есть чувство что лотус умеет фиксировать "холостой Use"
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!