Lotusscript: редкие конструкции

  • Автор темы Yakov
  • Дата начала
T

turumbay

Игры в singleton.
Классический (GOF) синглтон на LS не реализуем во-первых, из-за невозможности создать приватный конструктор класса и, во-вторых, из-за "локального" контекста выполнения(отсутствия переменных, глобальных на уровне приложения). Проблемы глобальной видимость здесь трогать не буду, а вот за проблему приватного конструктора есть некоторые мысли...
В свое время было найден workaround: .
Автор предлагает использовать в качестве синглтона приватный экземпляр приватного же класса, возвращая ссылку на него как на variant:
Код:
Private universe As TUniverse
Private Class TUniverse
Sub New()
Call BigBang()
End Sub
Private Function BigBang()
' Применяем(?) Большой Взрыв, для создания новой вселенной
End Function
End Class
Public Function getUniverse As Variant
If universe Is Nothing Then
Set universe = New TUniverse()
End If
Set getUniverse = universe
End Function
Идея, в общем, интересная, НО:
Предложенная реализация паттерна отвратительна тем, что приходится обращаться с объектом как с variant-ом - т.е. все очепятки клиента вылезут только на этапе выполнения. Кроме того невозможно создать функцию, принимающую объект указанного типа как параметр. Данный минус решения (IMHO) перевешивают все возможные плюсы. Забиваем.
Предлагаю на суд общественности альтернативное решение.
Раз нельзя сделать закрытый конструктор, сделаем так, чтоб его невозможно было вызвать. Небольшая доработка напильником:
Код:
Private universe As TUniverse
Private Class TFakeClass
Sub New()
End Sub
End Class
Public Class TUniverse
Sub New( i_fake As TFakeClass)
Call BigBang()
End Sub
Private Function BigBang()
' Применяем Большой Взрыв, для создания новой вселенной
End Function
End Class
Public Function getUniverse As TUniverse
If universe Is Nothing Then
Set universe = New TUniverse( Nothing )
End If
Set getUniverse = universe
End Function
И все прелести отлова ошибок на этапе компиляции снова доступны.
Т.к. конструктор требует параметром приватный класс - в клиентском коде создать новый экземпляр объекта не получится...
Единственная конструкция, которую пропустит компилятор - Dim clientSideUniverse As New TUniverse( Nothing ). Однако создать объект все равно не выйдет( ошибка времени выполнения ). При попытке унаследоваться от Вселенной с переопределением конструктора
Код:
Sub New() , TUniverse( Nothing )
End Sub
- также ляжет на этапе выполнения. Т.е. реально имеем паблик класс, экземпляр которого невозможно инстанцировать в клиентском коде. Эврика?

З.Ы. Идея на самом деле родилась для совершенно другой задачи. Фактически требовалось передавать в функцию значение из фиксированного набора( enumeration ). Городить case и проверять входной параметр внутри функции - не выход, т.к. компилятор все равно позволяет ошибиться в клиентском коде.
При помощи данной техники мы можем объявить нужное количество экземпляров класса и пользоваться ими как элементами перечисления: INVOICE_STATUS_BLOCKED , INVOICE_STATUS_APPROVED и т.д.( будучи уверенным, что вызвать функцию с неверным параметром клиенту не удастся )
 

ToxaRat

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

Klido

открываем почтовый шаблон (если текущий знаком - берем новую версию :mellow:) и там редкие конструкции встречаются - почувствуй себя исследователем, как говорится...
думают, думают и придумывают...
повесили в 8.5 шаблоне (меньше не смотрел с какого начали, наверное, с 8.0) в аутлайне на "цепочки сообщений" (и не только) сокрытие по @IsEmbeddedInsideWCT
смысл неочевиден...
Returns 1 (True) if any Notes content is open inside Workplace client (even bookmarks)
The Notes 8.0 Standard client returns a value of True, and the Notes 8.0 Basic client returns a value of False

В итоге в стандартном не видно этой вьюхи - правильно, но зачем её скрыли-то? а вдруг ещё что-то скрыли? да, скрыли :)

"Исходящие"! с комментом сокрытия REM { Hidden for now }; вычисляемым контекстом Action: @Command([FileOpenDatabase];"Mail.box")
вон куда они мыслят....

эт оя к тому, что "редкие" конструкции в почтовом шаблоне бывают реально редкими... в сл. версии шаблона их может уже не быть и никто никогда их больше не увидит :)
 
T

turumbay

ребята пишите, пишите, мне уже интересно что же топик сайдер имел ввиду и что же такое "редкое и экзотическое" я еще не знаю
глядишь сниму шляпу и переделаю что нибудь по новоузнанное :mellow:
Зачем это здесь? Взрослый дятька пытаеца самоутверждаца в песочнице для малышей?
Или тема топика "Lotusscript: редкие конструкции, которых еще не знает ToxaRat"?
P.S. И кто такой "топик сайдер"?
P.P.S. сорри за оффтоп.
 

ToxaRat

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

Взрослый дятька пытаеца самоутверждаца
дяько ужо давно утвердился, я подстегиваю, мну интересно шо будет ;)
 
M

morpheus

Ув. пользователи темы не для срача, отношения выясняем в личку
 

Darkhan

Green Team
14.12.2012
99
2
BIT
0
Столкнулся со следующей багофичей, связанной с областью видимости user-defined типов и классов:
1) Создаем библиотеку Test:
Код:
Option Public
Option Declare

%REM
Class Test
Description: Comments for Class
%END REM
Private Class Test

End Class
Sub Initialize

End Sub
%REM
Function getTest
Description: Comments for Function
%END REM
Public Function getTest() As Variant
Dim test As New Test
Set getTest = test
End Function
2) Создаем агент:
Код:
Option Public
Option Declare
Use "Test"
Sub Initialize
Call getTest()
[u][b]Dim j As Test[/b][/u]
End Sub
Опа-на ^_^ , приехали приватный класс, описанный в библиотеке теперь виден в агенте.
Идем дальше:
1) Модернизируем библиотеку
Код:
Option Public
Option Declare

%REM
Type PrivateType
Description: Comments for Type
%END REM
Private Type PrivateType
foo As Boolean
End Type
%REM
Class Test
Description: Comments for Class
%END REM
Public Class Test

%REM
Sub New
Description: Comments for Sub
%END REM
Sub New()
Dim pt As PrivateType
Print pt.foo
End Sub

End Class
Sub Initialize

End Sub

%REM
Function getTest
Description: Comments for Function
%END REM
Public Function getTest() As Variant
Dim test As New Test
Set getTest = test
End Function
2) и собственно агент
Код:
Option Public
Option Declare
Use "Test"
Sub Initialize
Call getTest()
[u][b]Dim pt As PrivateType[/b][/u]
End Sub
Вообще сели в лужу :wacko:
Получается, вызывая публичный метод библиотеки, в котором фигурируется приватный user-defined ти или класс (в теле метода, либо конструктора/деструктора), имеем возможность использовать эти типы/классы
Сие открытие "накрывает медным тазом" идею1 и идею2 создания синглтона на лотусе :rolleyes:
 
D

Dragon108

Столкнулся со следующей багофичей, связанной с областью видимости user-defined типов и классов:
1) Создаем библиотеку Test:
Код:
Option Public
Option Declare

%REM
Class Test
Description: Comments for Class
%END REM
Private Class Test

End Class
Sub Initialize

End Sub
%REM
Function getTest
Description: Comments for Function
%END REM
Public Function getTest() As Variant
Dim test As New Test
Set getTest = test
End Function
2) Создаем агент:
Код:
Option Public
Option Declare
Use "Test"
Sub Initialize
Call getTest()
[u][b]Dim j As Test[/b][/u]
End Sub
Опа-на :blink: , приехали приватный класс, описанный в библиотеке теперь виден в агенте.
Идем дальше:
1) Модернизируем библиотеку
Код:
Option Public
Option Declare

%REM
Type PrivateType
Description: Comments for Type
%END REM
Private Type PrivateType
foo As Boolean
End Type
%REM
Class Test
Description: Comments for Class
%END REM
Public Class Test

%REM
Sub New
Description: Comments for Sub
%END REM
Sub New()
Dim pt As PrivateType
Print pt.foo
End Sub

End Class
Sub Initialize

End Sub

%REM
Function getTest
Description: Comments for Function
%END REM
Public Function getTest() As Variant
Dim test As New Test
Set getTest = test
End Function
2) и собственно агент
Код:
Option Public
Option Declare
Use "Test"
Sub Initialize
Call getTest()
[u][b]Dim pt As PrivateType[/b][/u]
End Sub
Вообще сели в лужу :wacko:
Получается, вызывая публичный метод библиотеки, в котором фигурируется приватный user-defined ти или класс (в теле метода, либо конструктора/деструктора), имеем возможность использовать эти типы/классы
Сие открытие "накрывает медным тазом" идею1 и идею2 создания синглтона на лотусе B)
А если убрать в самом начале Option Public?


Option Public
Объявляет в модуле по умолчанию явное объявление ОВ Public.

Оператор используется в модуле только один раз. Он может предшествовать любым объявлениям в модуле. На уровне модуля оператор Option Public определяет ОВ для всех переменных, констант, процедур, типов и классов, определенные пользователем, а также для внешних процедур, и не определяет ОВ меток, переменных - ссылок или любых других неявно объявленных переменных.

Если переменная в типе, определенном пользователем или переменная - ссылка на объект имеют тип Public, то тип данных, на которые осуществляется ссылка, не могут быть типа Private. Ключевое слово Private отменяет действие Option Public.



Если заменить Type на Class то работает ... видимо для объявляемых типов больше не фурычит :(
 
T

turumbay

Столкнулся со следующей багофичей, связанной с областью видимости user-defined типов и классов:
Получается, вызывая публичный метод библиотеки, в котором фигурируется приватный user-defined ти или класс (в теле метода, либо конструктора/деструктора), имеем возможность использовать эти типы/классы
Наблюдение верное, вывод - нет. Компилятор действительно пропускает такую конструкцию, но воспользоваться этим не получится. Упадет в рантайме с соответвующим исключением. В исходном посте я указывал на возможность вызова
Код:
Dim clientSideUniverse As New TUniverse( Nothing )
, который нормально компилируется но вываливаеца с ошибкой во время выполнения. Т.е. автор библиотеки может быть уверен, что
  • имеем паблик класс, экземпляр которого невозможно инстанцировать в клиентском коде
  • при помощи данной техники мы можем объявить нужное количество экземпляров класса и пользоваться ими как элементами перечисления, будучи уверенным, что вызвать функцию с неверным параметром клиенту не удастся
При желании, обнаруженную вами ошибку компилятора можно обойти. Например, можно перекрыть приватный класс одноименным публичным (а-ля variable shadowing):
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">workaround</div></div><div class="sp-body"><div class="sp-content">
Создадим вспомогательную библиотеку Guard, содержащуую паблик версию нашего приватного класса(Fake) и паблик же класс Guard, принимающий экземпляр публичного Fake в конструкторе:
Код:
Option Public
Option Declare

Public Class Fake
End Class

Public Class Guard
Sub New(i_fake As Fake)
End Sub
End Class
Основная библиотека:
Код:
Option Public
Option Declare
Use "Guard"

Public universe As TUniverse

Private Class Fake ' Приватная версия Fake, которая перекрывает публичную из Guard
End Class

Public Class TUniverse
' Порядок аргументов важен: Guard должен идти перед Fake.
' Guard идет первым аргументом и т.к. сам требует "публичной" версии Fake, 
' то именно публичная версия будет видна компилятору в клиентском коде.
' Вторым аргументом конструктора ожидается приватная версия Fake, которая 
' становится действительно приватной.
Sub New(i_guard As Guard, i_fake As Fake) 
Call BigBang()
End Sub

Private Function BigBang()
' Применяем Большой Взрыв, для создания новой вселенной
End Function
End Class

Sub Initialize
Set universe = New TUniverse(Nothing, Nothing)
End Sub
Класс Fake можно заменить на Type - тогда, как вы справедливо заметили, в клиентском коде не прокатит создание объекта через nothing.
Guard должен быть классом, иначе Fake не перекроется.
 

Darkhan

Green Team
14.12.2012
99
2
BIT
0
Например, можно перекрыть приватный класс одноименным публичным (а-ля variable shadowing):
Лотус заставляет нас извращаться из-за своей неполноценности :blink:
Компилятор действительно пропускает такую конструкцию, но воспользоваться этим не получится. Упадет в рантайме с соответвующим исключением.
Действительно, слепо доверившись компилятору, я не удосужился проверить код при вызове B)
 
C

cLif

Игры в singleton.
Классический (GOF) синглтон на LS не реализуем во-первых, из-за невозможности создать приватный конструктор класса и, во-вторых, из-за "локального" контекста выполнения(отсутствия переменных, глобальных на уровне приложения). Проблемы глобальной видимость здесь трогать не буду, а вот за проблему приватного конструктора есть некоторые мысли...
В свое время было найден workaround: .
Автор предлагает использовать в качестве синглтона приватный экземпляр приватного же класса, возвращая ссылку на него как на variant:
Код:
Private universe As TUniverse
Private Class TUniverse
Sub New()
Call BigBang()
End Sub
Private Function BigBang()
' Применяем(?) Большой Взрыв, для создания новой вселенной
End Function
End Class
Public Function getUniverse As Variant
If universe Is Nothing Then
Set universe = New TUniverse()
End If
Set getUniverse = universe
End Function
Идея, в общем, интересная, НО:
Предложенная реализация паттерна отвратительна тем, что приходится обращаться с объектом как с variant-ом - т.е. все очепятки клиента вылезут только на этапе выполнения. Кроме того невозможно создать функцию, принимающую объект указанного типа как параметр. Данный минус решения (IMHO) перевешивают все возможные плюсы. Забиваем.
Предлагаю на суд общественности альтернативное решение.
Раз нельзя сделать закрытый конструктор, сделаем так, чтоб его невозможно было вызвать. Небольшая доработка напильником:
Код:
Private universe As TUniverse
Private Class TFakeClass
Sub New()
End Sub
End Class
Public Class TUniverse
Sub New( i_fake As TFakeClass)
Call BigBang()
End Sub
Private Function BigBang()
' Применяем Большой Взрыв, для создания новой вселенной
End Function
End Class
Public Function getUniverse As TUniverse
If universe Is Nothing Then
Set universe = New TUniverse( Nothing )
End If
Set getUniverse = universe
End Function
И все прелести отлова ошибок на этапе компиляции снова доступны.
Т.к. конструктор требует параметром приватный класс - в клиентском коде создать новый экземпляр объекта не получится...
Единственная конструкция, которую пропустит компилятор - Dim clientSideUniverse As New TUniverse( Nothing ). Однако создать объект все равно не выйдет( ошибка времени выполнения ). При попытке унаследоваться от Вселенной с переопределением конструктора
Код:
Sub New() , TUniverse( Nothing )
End Sub
- также ляжет на этапе выполнения. Т.е. реально имеем паблик класс, экземпляр которого невозможно инстанцировать в клиентском коде. Эврика?

З.Ы. Идея на самом деле родилась для совершенно другой задачи. Фактически требовалось передавать в функцию значение из фиксированного набора( enumeration ). Городить case и проверять входной параметр внутри функции - не выход, т.к. компилятор все равно позволяет ошибиться в клиентском коде.
При помощи данной техники мы можем объявить нужное количество экземпляров класса и пользоваться ими как элементами перечисления: INVOICE_STATUS_BLOCKED , INVOICE_STATUS_APPROVED и т.д.( будучи уверенным, что вызвать функцию с неверным параметром клиенту не удастся )

Оч интересная идея с фейк-классом! Спасибо!
Т.е. унаследоваться при таком подходе от класса-одиночки невозможно, я правильно понимаю?
 
Мы в соцсетях:

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