Robert Cemper · Apr 26, 2019 go to post

Dear Martin,

I have a rather clear vision  where your $example comes from ($zzg, $zza, ...)  wink
My personal suggestion is to move everything you maintain today in %ZZLANG?00 routines into clean Macro definitions (.inc)

The history of %LANG* code goes back to times when migration from other language dialects (MSM, DTM, DSM, VISOS, ..) happened
and developers were writing just in  .INT routines. That's far back in the late 80ies.  The availability of MACRO code (also ages back) made it almost obsolete. The feature was never eliminated by considerations of backward compatibility. 

I personally would never allow any developer to touch %SYS. 
And wouldn't accept any code using $zz* , zz* stuff or $zu().
There are much cleaner ways to achieve the same result without compromising the core. 

Robert Cemper · Apr 23, 2019 go to post

if you just look for a specific property instead of a larger part of the object
you may use 

set value=##class(ICT.Experiments.B).<propertyname>GetStored(primaryKey)

instead of 

set collB=##class(ICT.Experiments.B).%OpenId(primaryKey)

to avoid loading the full object

Robert Cemper · Apr 19, 2019 go to post

I may misunderstand your intentions but

when I use "ResultSet.%Get("Collection")", all I get is a list of the primary keys of the objects

now you all you miss for each PrimaryKey is 

Set collB=##class(ICT.Experiments.B).%OpenId(primaryKey) 

or

Set collC=##class(ICT.Experiments.C).%OpenId(primaryKey)

and the object is yours.

With your class definition,  PrimaryKey is the Idkey of the Object.

Robert Cemper · Apr 15, 2019 go to post

the total size is somewhat strange its format changes from 255 to 256 in size and interpretation
and again at 65535 / 65536   up to <MAXSTRING>
 

Robert Cemper · Apr 15, 2019 go to post

special case:

s a=$lb() zzdump a w !,$l(a)
 0000: 01                                                      .
1
s a=$lb("") zzdump a w !,$l(a)
 0000: 02 01
                                                  ..
2
s a="" zzdump a w !,$l(a)
0
Robert Cemper · Apr 15, 2019 go to post

the structure of $LB() is rather simply a binary string

-----------element--------------
TotalLength = 1, 3, 7 bytes depending on size    *corrected*
Type = 1 byte  (check in JSON converter for codes, or just check with ZZDUMP)
Content : size = TotalLength-1-size of length field
-----------element--------------
TotalLength = 1, 3, 7 bytes depending on size    *corrected*
Type = 1 byte  (check in JSON converter for codes, or just check with ZZDUMP)
Content : size= TotalLength-1-size of length field
-----------element--------------

...

Therefore concatenation of $lb) is so easy

Robert Cemper · Apr 10, 2019 go to post

Sorry,  I had more changes. 
My approach in details

Class DC.String Extends %String  {
ClassMethod Get() As %String [ CodeMode = objectgenerator ]
{    do %code.WriteLine($c(9) _ "Quit $g(^Test.String, 0)")
    quit $$$OK  }
ClassMethod Set(%val As %String) [ CodeMode = objectgenerator ] {
    do %code.WriteLine($c(9) _ "Set ^Test.String = %val")
    do %code.WriteLine($c(9) _ "do zTest()")
    quit $$$OK }
/// this generates Method propTest()
/// but satisfies the Compiler for this class
ClassMethod Test() { quit  ;; from Data definition }
}

compiles this routine:

 ;DC.String.1
 ;(C)InterSystems, generated for class DC.String. Do NOT edit. 10/04/2019 12:00:42PM
 ;;42345370;DC.String
 ;
zGet() public  Quit $g(^Test.String, 0) }
zSet(%val) public Set ^Test.String = %val
      do zTest() }
zTest() public  quit  ;; from Data definition }

and the  using class

Class DC.StringTest Extends %RegisteredObject  {
Property prop As DC.String;
Method Test()
 b   quit ;; from using Class }
}

compiled as 

 ;DC.StringTest.1
 ;(C)InterSystems, generated for class DC.StringTest. Do NOT edit. 10/04/2019 12:02:35PM
 ;;49614632;DC.StringTest
 ;
%NormalizeObject() public {
If '$system.CLS.GetModified() Quit 1
If m%prop Set:i%prop'="" i%prop=(..propNormalize(i%prop))
Quit 1 }
%ValidateObject(force=0,checkserial=1) public {
set sc=1
If '$system.CLS.GetModified() Quit sc
If m%prop Set iv=..prop If iv'="" Set rc=(..propIsValid(iv)) If ('rc) Set sc=$$EmbedErr^%occSystem(sc,rc,5802,"prop",iv)
Quit sc }
zTest() public {
 b   quit ;; from using Class
}
zpropGet() public {
Quit $g(^Test.String, 0) }
zpropSet(%val) public {
Set ^Test.String = %val
do zTest() }
zpropTest() public {
 quit  ;; from Data definition
}

and the test

 SAMPLES>s obj=##class(DC.StringTest).%New()
SAMPLES>set obj.prop=123
 b   quit ;; from using Class
 ^
<BREAK>zTest+1^DC.StringTest.1
SAMPLES 3d1>

Well, the code generator can be tricky.
It's not one of my favorites. But sometimes you have no choice.

Robert Cemper · Apr 9, 2019 go to post

instead of 

do %code.WriteLine($c(9) _ "Quit ..Test()")

use

do %code.WriteLine($c(9) _ "Quit zTest()")

It worked for me best

Robert Cemper · Apr 9, 2019 go to post

OK.
StorageTo../..ToStorage only works in persistent classes where you move content from/to globals.
No chance without storage. 

It doesn't get called in Registered Classes and not when the object wasn't saved.
see my test with %Persistent

set obj=##class(Test.String).%New()
write 
obj.prop    ;nothing loaded yet
set obj.prop=77 write obj.prop   ; unchanged as neither stored nor loaded
77
do obj.%Save(),obj,%Reload() ; force reload to trigger StorageToLogical
write obj.prop  ; and here we go
prop


This proves that there is limited use of the approach.

Robert Cemper · Apr 8, 2019 go to post

I could imagine inheriting standard data types for a customized data type and then 

adding methods LogicalToStorage and StorageToLogical  similar as LogicalToObs, ....
So your manipulations happen on the way from Global to the local variable.

Additional Parameters eventually may control the generated code.

It's just a vague idea.

Robert Cemper · Apr 8, 2019 go to post

Ken Olson , the founder of DEC (Digital Equipment Corp.) was  famous for its statement:

  • "I can't imagine any good reason for someone to have a computer at his home"

 Similar in the late 1950ies IBM estimated the worldwide market for computers of 15..30 systems in total.

So lack of phantasy what could be in the future is quite common also for very successful people and companies.

Robert Cemper · Apr 6, 2019 go to post

inside &SQL() only SQL compatible code is allowed
so $ZDT($H,3,1,3) is not known in SQL

you may do

set %myts=$ZDT($H,3,1,3), %tx=tx
&sql(SELECT {fn TIMESTAMPDIFF(SQL_TSI_HOUR,:%myts,:%tx)})

mind the colon :%myts and :%tx to pass global  accessible variables to embedded SQL

Robert Cemper · Apr 1, 2019 go to post

you better not change   %CSP.Login but make a personal copy and change this

404 = HTTP page not found. Most likely you put your copy to the wrong directory or namespace   

And then you have to put the reference in MgmtPortal Security-> WebApplications as Login page:
Again with the correct namespace and the correct directory.

Robert Cemper · Mar 26, 2019 go to post

can't import %routines which I need. 

Without any special mapping, %routines are stored in SYSLIB. (except %z*,%Z*)

Mount SYSLIB (default: read-only) as Read/Write and you can load your %routines. 

Needless to mention that you better not overwrite already existing %routines.
The effects could be unpredictable.

Robert Cemper · Mar 26, 2019 go to post

As you describe it I'd create a nice BAT file that you execute.
It coud be static or created ad hoc just by writing it from Caché

And then execute it using $ZF(-1...) ,$zf(-2....) or CPIPE 

Though Caché has powerful utilities around %File class you will be faster that way

[based on ~40 yrs of M]

Robert Cemper · Mar 21, 2019 go to post

to create your own Login Page you best start with  Class  %CSP.Login and adapt it to your specific needs.

defaulting to

and then you add the new Login Page to Security-> WebApplications

Robert Cemper · Mar 16, 2019 go to post

Size of WIJ is in Relation to Global   Buffers. With equal size of G.Buf. you should get similar size  of WIJ

Robert Cemper · Mar 11, 2019 go to post

that's wrong !  "will execute nothing, "   

if condition

Sets the system variable $TEST.   
And this was and still is a widely used way of signaling between routines and functions.
And millions lines of existing code rely on its proper use.

I come back to an earlier comment: Really learning the language is definitely an advantage.

Robert Cemper · Mar 11, 2019 go to post

returning to dotted subroutines would be really bad. Though they are still around in %SYS.  laugh

on the other hand, the flexibility of the language allows a broad range of personal styles.
knowing them enabled me in the past (amongst my customers ) to identify the author of a routine
just by his style with a hit rate of >75%.  devil

Robert Cemper · Mar 11, 2019 go to post

OK Vitaly !

It happens under cover  (from: ^%SYS.SECURITY1.int

Set $zt="SSLConfigError"
'($e($roles,1,$l("%All"))="%All") $ET,$roles $ET="",$roles=$roles_","_"%All"}
  $namespace
Do $zu(5,"%SYS")

 
Robert Cemper · Mar 11, 2019 go to post

Alexej,

if you don't care about maintenance effort the most exact pointer is preferable.

As you may see from Ensemble the number of entries in the mapping table is of no importance.
With modern hardware, saving memory is of no importance anymore.

Robert Cemper · Mar 10, 2019 go to post

I remember times when new programmers learned from their masters to use no matter what
programming language in her full beauty and elegance with all its features.
no matter if this was Assembler/360 or Macro32 or C, C++, C# or Bliss or PL/1 or Fortran, Algol, .... [list almost unlimitted]

All of them had their tricks and open and hidden features that inspired the creativity of developers
and allowed them to create artwork instead of stereotypic formulated phrases. By this approach,
developers get degraded from architects to monotone brick assemblers.

"users unfamiliar with the language" 
I'd recommend they should learn it to understand it before touching it.
If I want to read the Правда  I have to learn Cyrillic characters and the Russian language to understand it.
Nobody would accept any request for Latin letters.

Robert Cemper · Mar 10, 2019 go to post

Hmmm,
it seems to prefer "waste screen space" style 
over "have all on 1 screen with no scrolling"   [my favorite ]