synopse / mORMot

Synopse mORMot 1 ORM/SOA/MVC framework - Please upgrade to mORMot 2 !
https://synopse.info
785 stars 323 forks source link

Documentation example mistake ? 4.3.1. TList-like properties #425

Closed mingodad closed 2 years ago

mingodad commented 2 years ago

Going through the documentation it seems that the examples at 4.3.1. TList-like properties has a mistake:

for i := GroupA.Count-1 downto 0 do
    if i and 3=0 then ///!!!!<<<< here it seems that it shoudl be "GroupA[3] = 0" or something similar
      GroupA.Delete(i); // delete integer at index i
synopse commented 2 years ago

Hello, Please use https://synopse.info/forum for such discussion: this is not worth opening a ticket, until a bug is really identified.

This sample is correct. if i and 3=0 then Does make sense: it erases one fourth of the entries, per index. It is the same as if i mod 4=0 - just slightly faster. In fact, this is what the regression tests do, with no problem.

mingodad commented 2 years ago

Thank you for your help ! After your answer I made a console application to test it and indeed it works, the problem is that I'm used to C/C++ like laguages and the expression and it's style (spaces without grouping) i and 3=0 seems like comparing two constants and it's result been tested against i with and operator, but in realisty the expression is (i and 3) = 0 or in C/C++ like languages something like (i % 3) == 0.

I did some work in pascal in the past and evaluating using it again with mORMot and I'm not sure if this style of code formatting is a good one for the readability point of view because it seem to induce confusing/wrong interpretation like I did. Again thank you for your time and dedication !

synopse commented 2 years ago

Operator precedence in the pascal language does more sense than in C/C++ for sure.

mingodad commented 2 years ago

But a bit of formatting doesn't hurt !

mingodad commented 2 years ago

And that we are at the documentation examples I'm trying to build/execute 4.4.1.1. Variant object documents example and it has a variable that is not declared/initialized (although it has ... to denote missing pieces) and as I said before been new again to pascal and mORMot it makes a bit harder to understand/evaluate it through the documentation examples:

var Doc1,Doc2: [TDocVariantData](https://synopse.info/files/html/api-1.18/SynCommons.html#TDOCVARIANTDATA);
 ...
  Doc1.Init; // needed for proper initialization
  assert(Doc1.Kind=dvUndefined);
  Doc1.AddValue('name','John');        // add some properties
  Doc1.AddValue('birthyear',1972);
  assert(Doc1.Kind=dvObject);          // is now identified as an object
  assert(Doc1.Value['name']='John');    // read access to the properties (also as varByRef)
  assert(Doc1.Value['birthyear']=1972);
  assert(Doc1.U['name']='John');        // slightly faster read access
  assert(Doc1.I['birthyear']=1972);
  writeln(Doc1.ToJSON); // will write '{"name":"John","birthyear":1972}'
  Doc1.Value['name'] := 'Jonas';      // update one property
  writeln(Doc1.ToJSON); // will write '{"name":"Jonas","birthyear":1972}'
  Doc2.InitObject(['name','John','birthyear',1972],
///<<<<!!!!<<< here aOptions is undefined
    aOptions+[dvoReturnNullForUnknownProperty]); // initialization from name/value pairs 
///>>>>
  assert(Doc2.Kind=dvObject);
  assert(Doc2.Count=2);
  assert(Doc2.Names[0]='name');
  assert(Doc2.Values[0]='John');
  writeln(Doc2.ToJSON);         // will write '{"name":"John","birthyear":1972}'
  Doc2.Delete('name');
  writeln(Doc2.ToJSON);         // will write '{"birthyear":1972}'
  assert(Doc2.U['name']='');
  assert(Doc2.I['birthyear']=1972);
  Doc2.U['name'] := 'Paul';
  Doc2.I['birthyear'] := 1982;
  writeln(Doc2.ToJSON);         // will write '{"name":"Paul","birthyear":1982}'

Thanks again for your help, time and dedication !

mingodad commented 2 years ago

Replacing aOptions+[dvoReturnNullForUnknownProperty] by Doc2.Options+[dvoReturnNullForUnknownProperty] allow it to build/run.

synopse commented 2 years ago

Please use our forum for such discussion.

mingodad commented 2 years ago

I'm trying to register the forum but it ask for What is the UPPERCASE name of the CURRENT editor of Delphi? (hint: E..O) and as I said I'm new again to Pascal (Freepascal/Delphi) and I don't know it ?

mingodad commented 2 years ago

I was going to report this problem with this documetnatio example 4.4.1.3. Variant array documents:

var V1,V2: variant; // stored as any variant
 ...
  V1 := [_Arr](https://synopse.info/files/html/api-1.18/SynCommons.html#_ARR)(['John','Mark','Luke']);
  V2 := [_Obj](https://synopse.info/files/html/api-1.18/SynCommons.html#_OBJ)(['name','John','array',[_Arr](https://synopse.info/files/html/api-1.18/SynCommons.html#_ARR)(['one','two',2.5])]); // as nested array
writeln([VariantSaveJson](https://synopse.info/files/html/api-1.18/SynCommons.html#VARIANTSAVEJSON)(V1));
 writeln(V1);  // implicit conversion from variant into string
 // both commands will write '["John","Mark","Luke"]'
 writeln([VariantSaveJson](https://synopse.info/files/html/api-1.18/SynCommons.html#VARIANTSAVEJSON)(V2));
 writeln(V2);  // implicit conversion from variant into string
 // both commands will write '{"name":"john","array":["one","two",2.5]}'
writeln(V1._Count); // will write 3 i.e. the number of items in the array document
  writeln(V1._Kind);  // will write 2 i.e. ord(dvArray)
  for i := 0 to V1._Count-1 do
    writeln(V1.Value(i),':',V2._(i));    // Value() or _() pseudo-methods
  // will write in the console:
  //  John John
  //  Mark Mark
  //  Luke Luke
  if V1.Exists('John') then             // Exists() pseudo-method
    writeln('John found in array');
  V1.Add('new item');                   // add "new item" to the array
  V1._ := 'another new item';           // add "another new item" to the array
  writeln(V1);          // will write '["John","Mark","Luke","new item","another new item"]'
  V1.Delete(2);
  V1.Delete(1);
  writeln(V1);          // will write '["John","Luke","another new item"]'
program mytlistlikeprop;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes, SysUtils, CustApp, SynCommons
  { you can add units after this };

type

  { TlistLikeProp }

  TlistLikeProp = class(TCustomApplication)
  protected
    procedure DoRun; override;
  public
    constructor Create(TheOwner: TComponent); override;
    destructor Destroy; override;
    procedure WriteHelp; virtual;
  end;

{ TlistLikeProp }

procedure TlistLikeProp.DoRun;
type
   TGroup = array of integer;
var
  Group: TGroup;
  GroupA: TDynArray;
  i, v: integer;
  ErrorMsg: String;
  bv: Boolean;
  Doc1,Doc2: TDocVariantData;
  var V1,V2: variant; // stored as any variant
begin
  // quick check parameters
  ErrorMsg:=CheckOptions('h', 'help');
  if ErrorMsg<>'' then begin
    ShowException(Exception.Create(ErrorMsg));
    Terminate;
    Exit;
  end;

  // parse parameters
  if HasOption('h', 'help') then begin
    WriteHelp;
    Terminate;
    Exit;
  end;

  { add your program here }
    GroupA.Init(TypeInfo(TGroup),Group); // associate GroupA with Group
    for i := 0 to 1000 do
    begin
      v := i+1000; // need argument passed as a const variable
      GroupA.Add(v);
    end;
    v := 1500;
    if GroupA.IndexOf(v)<0 then // search by content
      Writeln('Error: 1500 not found!');
    for i := GroupA.Count-1 downto 0 do
    begin
      //bv := (i and 3) = 0;
      //Writeln('Loop at ', i, ' value ', bv);
      if (i and 3) = 0 then
        GroupA.Delete(i); // delete integer at index i
    end;

    Doc1.Init; // needed for proper initialization
    assert(Doc1.Kind=dvUndefined);
    Doc1.AddValue('name','John');        // add some properties
    Doc1.AddValue('birthyear',1972);
    assert(Doc1.Kind=dvObject);          // is now identified as an object
    assert(Doc1.Value['name']='John');    // read access to the properties (also as varByRef)
    assert(Doc1.Value['birthyear']=1972);
    assert(Doc1.U['name']='John');        // slightly faster read access
    assert(Doc1.I['birthyear']=1972);
    writeln(Doc1.ToJSON); // will write '{"name":"John","birthyear":1972}'
    Doc1.Value['name'] := 'Jonas';      // update one property
    writeln(Doc1.ToJSON); // will write '{"name":"Jonas","birthyear":1972}'
    Doc2.InitObject(['name','John','birthyear',1972],
      Doc2.Options+[dvoReturnNullForUnknownProperty]); // initialization from name/value pairs
    assert(Doc2.Kind=dvObject);
    assert(Doc2.Count=2);
    assert(Doc2.Names[0]='name');
    assert(Doc2.Values[0]='John');
    writeln(Doc2.ToJSON);         // will write '{"name":"John","birthyear":1972}'
    Doc2.Delete('name');
    writeln(Doc2.ToJSON);         // will write '{"birthyear":1972}'
    assert(Doc2.U['name']='');
    assert(Doc2.I['birthyear']=1972);
    Doc2.U['name'] := 'Paul';
    Doc2.I['birthyear'] := 1982;
    writeln(Doc2.ToJSON);         // will write '{"name":"Paul","birthyear":1982}'

    V1 := _Arr(['John','Mark','Luke']);
    V2 := _Obj(['name','John','array',_Arr(['one','two',2.5])]); // as nested array
    writeln(VariantSaveJson(V1));
    writeln(V1);  // implicit conversion from variant into string
    // both commands will write '["John","Mark","Luke"]'
    writeln(VariantSaveJson(V2));
    writeln(V2);  // implicit conversion from variant into string
    // both commands will write '{"name":"john","array":["one","two",2.5]}'

    writeln(V1._Count); // will write 3 i.e. the number of items in the array document
    writeln(V1._Kind);  // will write 2 i.e. ord(dvArray)
    for i := 0 to V1._Count-1 do
      writeln(V1.Value(i),':',V2._(i));    // Value() or _() pseudo-methods
    // will write in the console:
    //  John John
    //  Mark Mark
    //  Luke Luke
    if V1.Exists('John') then             // Exists() pseudo-method
      writeln('John found in array');
    V1.Add('new item');                   // add "new item" to the array
    V1._ := 'another new item';           // add "another new item" to the array
    writeln(V1);          // will write '["John","Mark","Luke","new item","another new item"]'
    V1.Delete(2);
    V1.Delete(1);
    writeln(V1);          // will write '["John","Luke","another new item"]'

  // stop program loop
  Terminate;
end;

constructor TlistLikeProp.Create(TheOwner: TComponent);
begin
  inherited Create(TheOwner);
  StopOnException:=True;
end;

destructor TlistLikeProp.Destroy;
begin
  inherited Destroy;
end;

procedure TlistLikeProp.WriteHelp;
begin
  { add your help code here }
  writeln('Usage: ', ExeName, ' -h');
end;

var
  Application: TlistLikeProp;
begin
  Application:=TlistLikeProp.Create(nil);
  Application.Title:='myTlistLikeProp';
  Application.Run;
  Application.Free;
end.

Output (Freepascal 3.2):

./tlistlikeprop
{"name":"John","birthyear":1972}
{"name":"Jonas","birthyear":1972}
{"name":"John","birthyear":1972}
{"birthyear":1972}
{"birthyear":1982,"name":"Paul"}
["John","Mark","Luke"]
["John","Mark","Luke"]
{"name":"John","array":["one","two",2.5]}
{"name":"John","array":["one","two",2.5]}
3
2
John:Exception at 000000000051D294: EVariantDispatchError:
No variant method call dispatch.
synopse commented 2 years ago

Please use the forum for such discussion. And put the source code in a separated ready-to-be-downloaded file, e.g. on gist.