You are not logged in.
I have a look at the mORMot2 repository from time to time. I like what I see very much. This morning I saw that the class TSQLRecord was renamed to TORM. English is not my natural language. But I feel that the new name was not chosen very happily. In my personal feeling TORMRecord or TORMObject would have been more understandable. But this is only my subjective opinion and should not be a criticism. I only wrote the note because at the current stage of development there are still all possibilities.
Arnaud, thank you very much for the wonderful work.
With best regards
Thomas
Offline
The idea is that instead of writing:
type
TSQLRecordBlogArticle = class(TSQLRecord)
...
we write with mORMot 2:
type
TORMBlogArticle = class(TORM)
...
I don't find this new code confusing.
TORM for the base class to inherit from an ORM persisted class doesn't seem to confusing.
Then we have TRest and TRestORM for the client or server process side (instead of a single bloated TSQLRest class), and TRest* associated types.
TORMRecord and TORMObject won't add anything else, and are confusing because we define a class, not a record or an object type.
And TORMClass is not a good idea, because usually T*Class is a metaclass, like TORMClass = class of TORM.
We get rid of all TSQL* names, and keep SQL only for mormot.db.sql.*.pas units, which are actually SQL processing units.
Our ORM is not SQL-only, it was in the beginning, but since years it is NoSQL too, as it can use for instance MongoDB.
But any feedback and ideas are welcome.
Offline
At first glance I also found it strange.
But considering that ORM alone is already an abbreviation that defines the concept of the class, I believe it makes sense.
And as the convention is maintained, the name of the final class will not be changed.
TORMCustomer = class(TORM)
TORMCustomer = class(TORMRecord)
TORMCustomer = class(TORMAnything)
//We will have TORMCustomer anyway.
Offline
This forum thread will be used as comments and feedback about the new names in mORMot2.
I just wrote a blog post:
https://blog.synopse.info/?post/2020/10 … 2-Renaming
Offline
My initial feeling is that, isn't mORMot follows the Active Record pattern? Then maybe record is easier to be understood?
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
The new name is perfect for me. Have much make sense.
Esteban
Offline
I have made another pass or types renaming in mORMot 2.
It sounds consistent everywhere now.
We will write for instance with mORMot 2:
type
TOrmBlogArticle = class(TOrm)
...
Check the latest versions of the https://github.com/synopse/mORMot2 repository.
Offline
ab wrote:I have made another pass or types renaming in mORMot 2.
It sounds consistent everywhere now.You may think renaming all TSyn* prefix too.
You remind me of some of the naming conflicts, such as TTextWritter - sometimes I have to use SynCommons.TTextWritter
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
edwinsn,
Some frameworks/libs use the same prefix for all types (e.g. Indy, TMS, JEDI, DevExpress, etc) but, even though it could minimize eventual collision names, it's not perfect as anyone can use the same prefix as other already has used.
It could be very verbose either. Imagine typing TMormotTextWritter or TMormotOrm (!!).
Simple names are better to read, however it could have colision... difficult decison.
However, in my opinion, if the framework/lib uses an abstract prefix (e.g. Id, Jv, dx, etc), it must be in all types. That is consistency.
Offline
edwinsn,
Some frameworks/libs use the same prefix for all types (e.g. Indy, TMS, JEDI, DevExpress, etc) but, even though it could minimize eventual collision names, it's not perfect as anyone can use the same prefix as other already has used.
It could be very verbose either. Imagine typing TMormotTextWritter or TMormotOrm (!!).
Simple names are better to read, however it could have colision... difficult decison.
However, in my opinion, if the framework/lib uses an abstract prefix (e.g. Id, Jv, dx, etc), it must be in all types. That is consistency.
Yes, we shouldn't use a prefix that's too long.
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
To sumup, the prefix are the following:
- TSyn* for core types
- TRTTI* for RTTI
- TOrm* for ORM process
- TRest* for REST process
- TInterface* for interface process
- TService* for service process
- TNet* THttp* TWebSockets* for communication
- and so on...
So I guess it won't be a good idea to get rid of the TSyn* prefix.
Offline
You remind me of some of the naming conflicts, such as TTextWritter - sometimes I have to use SynCommons.TTextWritter
It becomes a none issue if you stick to the correct uses clause unit order :
{RTL}
{Libraries}
{Personal}
But then again if you're in a VCL project the IDE will be happy to shit all over your uses clause.
Offline
We will write for instance with mORMot 2:
type TOrmBlogArticle = class(TOrm) ...
.
Would prefer this :
type
TBlogArticle = class(TSynORM)
...
I think I would prefer one common prefix for everything (TSyn* looks very good), for several reasons but mostly because in pascal, this has been the norm for libraries.
And you don't have to necessarily loose other prefixes, for example :
type
TSynRecordRTTI = class(TSynRttiType)
...
Offline
ab wrote:We will write for instance with mORMot 2:
type TOrmBlogArticle = class(TOrm) ...
.
Would prefer this :
type TBlogArticle = class(TSynORM) ...
I think I would prefer one common prefix for everything (TSyn* looks very good), for several reasons but mostly because in pascal, this has been the norm for libraries.
And you don't have to necessarily loose other prefixes, for example :
type TSynRecordRTTI = class(TSynRttiType) ...
I completely agree with you! `TSyn` for all types.
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
edwinsn wrote:You remind me of some of the naming conflicts, such as TTextWritter - sometimes I have to use SynCommons.TTextWritter
It becomes a none issue if you stick to the correct uses clause unit order :
{RTL}
{Libraries}
{Personal}But then again if you're in a VCL project the IDE will be happy to shit all over your uses clause.
That's what I've been doing for years and works (mostly time).
[...]
I completely agree with you! `TSyn` for all types.
Comparing mORMot2 vs first one, it seems that Arnaud was replacing all Synopse "Syn" references, using clean prefixes only related with the modules... that's what I thought.
We know that "Syn" stands for Synopse, but is it consistent with the rest of code? I'm asking because the main prefix for all units now is "mormot", no more "Syn".
Offline
I think Pascal should have a syntax that could end this discussion about using or not prefixes:
uses
mormot.core.base as mcore;
function Clean(const aValue: RawUTF8): RawUTF8;
begin
result := mcore.Trim(aValue);
end;
Even better it would be, if we can use the same alias for more than one unit:
uses
mormot.core.base as mormot;
mormot.core.datetime as mormot;
function MyTrim(const aValue: RawUTF8): RawUTF8;
begin
result := mormot.Trim(aValue);
end;
function MyIso8601ToDateTime(const aValue: RawByteString): TDateTime;
begin
result := mormot.Iso8601ToDateTime(aValue);
end;
So, if you got any conflict, you just need to use an alias (a little one) as prefix!
Offline
+1 TSyn for all types.
TSynRTTI, TSynOrm, TSynRest, TSynInterface, TSynService, TSynNet
Offline
To sumup, the prefix are the following:
- TSyn* for core types
- TRTTI* for RTTI
- TOrm* for ORM process
- TRest* for REST process
- TInterface* for interface process
- TService* for service process
- TNet* THttp* TWebSockets* for communication
- and so on...So I guess it won't be a good idea to get rid of the TSyn* prefix.
I'm fully agree with this pattern @ab. It's very semantic, consistent and furthermore the simpler the better.
IMHO TSyn* for all types is not necessary at all. When we use some type (ie TOrm), you are in a "bounded context" where each type has its meaning in the context of its domain.
If there is a conflict, there are several easy solutions.
Last edited by xalo (2020-10-28 14:55:32)
Offline
For core types, we use TSyn* because the root class already exist.
For example, we used TSynDictionary or TSynQueue because TDictionary and TQueue already exist in the RTL.
Devil's Advocate: if Delphi introduce a new TOrm class, will you rename the current TOrm class to TSynOrm (breaking the code)?
If not, IMHO this argument hasn't much sense... I mean, we don't control others frameworks/libs naming.
IMO, either we use a (abstract) prefix in all class or just simple names, doesn't matter what others are doing out there.
Offline
edwinsn,
Some frameworks/libs use the same prefix for all types (e.g. Indy, TMS, JEDI, DevExpress, etc) but, even though it could minimize eventual collision names, it's not perfect as anyone can use the same prefix as other already has used.
It could be very verbose either. Imagine typing TMormotTextWritter or TMormotOrm (!!).
That is a problem with the syntax. Ruby solve this using modules and works great.
Offline
Your remark is purely rhetorical.
An official Delphi TOrm class won't be in SysUtils and other basic RTL units, so it won't affect our code.
It won't affect the mORMot code itself, but it affects we users of mORMot - because we might use both of those units.
Using a unified, short prefix for all types is a best practice that's been proven, to prevent existing and future conflicts.
As a strong example, If we use TSynTextWriter instead of just TTextWriter, it won't have been conflicted with System.Classes.TTextWriter.
Last edited by edwinsn (2020-10-29 07:29:52)
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
A common prefix makes the class's origin easily identifiable.
In code and elsewhere.
For example, anyone who sees a question on the stackoverflow about http communication and sees something like:
Cli: TIdHTTP
Easily identifies that indy is being used.
Offline
The new naming scheme seems fine to me.
Prefixing everything with Syn just because someone might have naming conflicts seems a bit of overkill.
Offline
If it were a change in a production framework I would agree that it would be unnecessary.
But it is a new version where other changes are already being made that will force refactoring.
So the time to change is now, after it is released it will no longer make sense...
Offline
I'm fully agree with this pattern @ab. It's very semantic, consistent and furthermore the simpler the better.
IMHO TSyn* for all types is not necessary at all. When we use some type (ie TOrm), you are in a "bounded context" where each type has its meaning in the context of its domain.
If there is a conflict, there are several easy solutions.
Bounded context for new projects from scratch, you're right.
But I'm used to maintain old projects, which mostly never used mORMot, and it could be very hard to do a refactoring to use mORMot when those conflicts pop up. But yes, there are several solutions.
Offline
If it were a change in a production framework I would agree that it would be unnecessary.
But it is a new version where other changes are already being made that will force refactoring.
So the time to change is now, after it is released it will no longer make sense...
You can do this:
type
TSynTextWriter = SynCommons.TTextWriter;
{...many others...}
{...even functions...}
If you use a lot, you may think create an include file "syncommons.alias.inc"—I prefer writing in each unit, though.
Last edited by mdbs99 (2020-10-29 15:28:39)
Offline
@mdbs99
Yes, I know about this possibility.
But I don't know if it's good practice.
I think it adds unnecessary complications.
I am referring, that as it will be a new version of the framework, there is not so much problem in changing the name of all classes to prefix with TSyn.
Many have already changed and the refactoring is inevitable.
Offline
@mdbs99
I am referring, that as it will be a new version of the framework, there is not so much problem in changing the name of all classes to prefix with TSyn.
Many have already changed and the refactoring is inevitable.
I understand and agree what you said. Now is a great (maybe only) time to decide on the prefix. And Prefixing all types with TSyn is a good choice.
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
I agree with prefixing the framework with TSyn*, historically Delphi third party frameworks have used this. Even more, functions and procedure they should have a prefix, but thats is more complex for compatibility. It's just another opinion.
Esteban
Offline
Since there is no commonly used naming convention for packages and package members in the Pascal word we should look how it done in other languages.
For example GoLang directly notes to SIMPLIFY a package member names - see https://blog.golang.org/package-names#TOC_3.
In mormot2 unit names is organized very well, so function\classes names inside units can be simple and omit a prefixes. TOrm is OK
For function/classes what conflicts with RTL prefix is a good idea. TSynDictionary is OK because TDictionary alrady in RTL
So, my opinion - @ab did all very well.
Offline
I agree with prefixing the framework with TSyn*, historically Delphi third party frameworks have used this. Even more, functions and procedure they should have a prefix, but thats is more complex for compatibility. It's just another opinion.
TSyn prefix for all types are good, but I don't think we need prefix for procedures and functions - it's not a common practice IMHO. We can just use fully qualified names for procedures and functions. for example: `unit1.procedure1`
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
We can just use fully qualified names for procedures and functions. for example: `unit1.procedure1`
Your example is not relevant because mORMot 2 uses long units names. In my opinion, using prefixes is preferable.
mormot.core.base.TrimU()
SynTrim()
Offline
Maybe a framework/lib shouldn't export any procedure or function, only types. These prevent any compilation issues, as you can't use a type—which has the same name for another—in arguments that doen't fit in.
We already have objects and classes. Why should I export for users—in interface section—functions if I can code an plain-object with a group of functions, which has the same context, on it?
TrimU() could have any context... but what about this:
TSynString = object
public
function Trim(const aValue: RawUTF8): RawUTF8;
function Copy(...
// etc...
end;
TSynDateTime = object
public
function Iso8601ToDateTime(const S: RawByteString): TDateTime; overload;
function Iso8601ToDateTimePUTF8Char(P: PUTF8Char; L: integer = 0): TDateTime;
{$ifdef HASINLINE}inline;{$endif}
procedure Iso8601ToDateTimePUTF8CharVar(P: PUTF8Char; L: integer; var result: TDateTime);
// etc...
end;
Using "Syn" as a prefix is another discussion... it was just an example.
But if these types have or not a prefix, I can still "rename a lot of functions", if I want to, instead each function:
type
TMormotStringHelper = mormot.core.base.TSynString;
Last edited by mdbs99 (2020-10-31 16:39:20)
Offline
Shouldn't these methods be static? (class methods)
Or your suggestion ist to maintain a global instance of the created objects?
TSynString = object
public
class function Trim(const aValue: RawUTF8): RawUTF8;
end;
Offline
Shouldn't these methods be static? (class methods)
You can't use "class function" in object types—it compiles the object (witch is strange), but if you write TSynString.Trim(), you'll get a compile error.
Or your suggestion ist to maintain a global instance of the created objects?
It is up to you.
Last edited by mdbs99 (2020-10-31 22:14:45)
Offline
Shouldn't these methods be static? (class methods)
Or your suggestion ist to maintain a global instance of the created objects?
TSynString = object public class function Trim(const aValue: RawUTF8): RawUTF8; end;
Won't compile. That should be
TSynString = class <--- here
public
class function Trim(const aValue: RawUTF8): RawUTF8;
end;
Offline
No conclusion yet from @ab as to whether or not to use the universal 'TSyn' type prefix
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
The TSyn* prefix is for classes only, which may conflict with Delphi or FPC RTL basic units.
Then direct functions would be fine. If there is some conflict potentiality, then some inlined function with an uniique name will be define, e.g. as TrimU() redirects to Trim().
Offline
Good decision. Just as I thought
Delphi XE4 Pro on Windows 7 64bit.
Lazarus trunk built with fpcupdelux on Windows with cross-compile for Linux 64bit.
Offline
Small amendments related to the names of functions (not classes, class procedures, etc).
mORMot is not alone when you develop a project,
I have to write alot of code mixed between string and RawUTF8 types.
And because in uses section the RTL (like SysUtils) are always goes before any libraries (like SynCommons), it's very annoying to write SysUtils.Trim() everywhere where the strings are used.
I'll be happy to see distinct prefixes/postfixes in mORMot for all collisions with standard Delphi utils (like SynTrim, TrimU, etc.)
As for classes the distinct prefix TSyn, TSy will be good for recognition and good for avoiding with any other libraries and frameworks (the common names like TService could collides very easilly if you have 2-3 libraries/services working with TService from mORMot, TService from library and your own domain core class TCustomService, so TSynService looks better, IMHO)
Offline
@Eugene
Those are fair points.
For some functions, like Trim() the easiest is to create an overload in SynCommons/mormot.core.base to also handle string, and don't use SysUtils.
Please check https://synopse.info/fossil/info/a306cc3a23
What do you think of making a list of colliding types in mORMot?
Offline
Doesn't it take more work to locate these possible collisions, and create the overloaded methods, than just adding the prefix?
Even if a collision list is created, further collisions may occur in the future.
With a prefix everything is solved. No ambiguity, no additional work afterwards.
S: = SynTrim(s); // No doubt which method is being used
S: = Trim (s); //SysUtils.Trim? SynCommons.Trim? overloaded / not overloaded?
Offline
For some functions, like Trim() the easiest is to create an overload
Yea, it easy, but wait: [DCC Error] SynCommons.pas(24041): E2251 Ambiguous overloaded call to 'Trim'
SynTrim is a good name for this function that will fix all troubles.
Offline
SynTrim is a good name for this function that will fix all troubles.
I agree.
Offline
TrimU() is perhaps a better way.
But https://synopse.info/fossil/info/37016e9478 should fix the Trim() overloaded problem with pre-unicode Delphi.
Offline
What about a "helper" object/record with all string functions? Another one for Date/Time functions, and so on.
Those will have a plain name (which @ab likes) but no collision with RTL; they would keep together all routines that have the same context; we can use code-completion for search any function from those helpers.
IMHO, that would be a "win-win" solution.
Offline