Jump to content

Search the Community

Showing results for tags 'language'.

More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


  • Delphi Questions and Answers
    • Algorithms, Data Structures and Class Design
    • VCL
    • FMX
    • RTL and Delphi Object Pascal
    • Databases
    • Network, Cloud and Web
    • Windows API
    • Cross-platform
    • Delphi IDE and APIs
    • General Help
  • Delphi General Discussions
    • Tips / Blogs / Tutorials / Videos
    • Delphi Third-Party
    • Job Opportunities / Coder for Hire
    • I made this
  • Software Development
    • Project Planning and -Management
    • Software Testing and Quality Assurance
  • Community
    • Community Management

Find results in...

Find results that contain...

Date Created

  • Start


Last Updated

  • Start


Filter by number of...


  • Start




Found 4 results

  1. Hi all, I'm trying to find what is the meaning of those and what the compiler does with variables declared with with either [out] or [in], like these: TMyRecord = record [in] SrcPosition: TPoint; [out] DstPosition: TPoint; end; I've been trying to search on google and in the doc, but all I can find is references to the normal in and out keywords. Thanks!
  2. When writing libraries you sometimes want to provide users (that is, programmers) with a flexible API. If a specific part of your library can be used in different ways, you may want to provide multiple overloaded methods accepting different combinations of parameters. For example, IOmniPipeline interface from OmniThreadLibrary implements three overloaded Stage functions. function Stage(pipelineStage: TPipelineSimpleStageDelegate; taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload; function Stage(pipelineStage: TPipelineStageDelegate; taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload; function Stage(pipelineStage: TPipelineStageDelegateEx; taskConfig: IOmniTaskConfig = nil): IOmniPipeline; overload; Delphi’s own System.Threading is even worse. In class TParallel, for example, there are 32 overloads of the &Forclass function. Thirty two! Not only it is hard to select appropriate function; it is also hard to decode something useful from the code completion tip. Check the image below – can you tell which overloaded version I’m trying to call? Me neither! Because of all that, it is usually good to minimize number of overloaded methods. We can do some work by adding default parameters, but sometimes this doesn’t help. Today I’d like to present an alternative solution – configuration records and operator overloading. To simplify things, I’ll present a mostly made-up problem. You can download it from github. An example type TConnector = class public procedure SetupBridge(const url1, url2: string); overload; procedure SetupBridge(const url1, proto2, host2, path2: string); overload; procedure SetupBridge(const proto1, host1, path1, proto2, host2, path2: string); overload; // procedure SetupBridge(const proto1, host1, path1, url2: string); overload; end; This class expects two URL parameters but allows the user to provide them in different forms – either as a full URL (for example, ‘http://www.thedelphigeek.com/index.html’) or as (protocol, host, path) triplets (for example, ‘http’, ‘www.thedelphigeek.com’, ‘index.html’). Besides the obvious problem of writing – and maintaining – four overloads this code exhibits another problem. We simply cannot provide all four alternatives to the user! The problem lies in the fact that the second and fourth (commented out) overload both contain four string parameters. Delphi doesn’t allow that – and for a good reason! If we could define both at the same time, the compiler would have absolutely no idea which method to call if we write SetupBridge(‘1’, ‘2’, ‘3’, ‘4’). Both versions would be equally valid candidates! So – strike one. We cannot even write the API that we would like to provide. Even worse – the user may get confused and may expect that we did provide the fourth version and they try to use it. Like this: conn := TConnector.Create; try conn.SetupBridge('http://www.thedelphigeek.com/index.html', 'http://bad.horse/'); conn.SetupBridge('http://www.thedelphigeek.com/index.html', 'http', 'bad.horse', ''); conn.SetupBridge('http', 'www.thedelphigeek.com', 'index.html', 'http', 'bad.horse', ''); // this compiles, ouch: conn.SetupBridge('http', 'www.thedelphigeek.com', 'index.html', 'http://bad.horse/'); finally FreeAndNil(conn); end; Although the last call to SetupBridge compiles, it does something that user doesn’t expect. The code calls the second SetupBridge overload and sets url 1 to ‘http’ and url 2 to (‘www.thedelphigeek.com’, ‘index.html’, ‘http://bad.horse/’). Strike two. The output of the program proves that (all ‘1:’ lines should be equal, as should be all ‘2:’ lines): Last but not least – the API is not very good. When we need to pass lots of configuration to a method, it is better to pack the configuration into meaningful units. So – strike three and out. Let’s rewrite the code! A solution Records are good solution for packing configuration into meaningful units. Let’s try and rewrite the API to use record-based configuration. TURL = record end; TConnector2 = class public procedure SetupBridge(const url1, url2: TURL); end; Much better. Just one overload! Still, there’s a problem of putting information inside the TURL record. I could add a bunch of properties and write: url1.Proto := 'http'; url1.Host := 'www.thedelphigeek.com'; url1.Path := 'index.html'; url2.URL := 'http://bad.horse/'; conn2.SetupBridge(url1, url2); Clumsy. I have to declare two variables and type lots of code. No. I could also create two constructors and write: conn2.SetupBridge(TURL.Create('http', 'www.thedelphigeek.com', 'index.html'), TURL.Create('http://bad.horse/')); conn2.SetupBridge(TURL.Create('http://www.thedelphigeek.com/index.html'), TURL.Create('http://bad.horse/')); That looks better, but still – in the second SetupBridge call both TURL.Create calls look completely out of place. Do I have to pull back and rewrite my API like this? TConnector = class public procedure SetupBridge(const url1, url2: string); overload; procedure SetupBridge(const url1: string; const url2: TURL); overload; procedure SetupBridge(const url1, url2: TURL); overload; procedure SetupBridge(const url1: TURL; const url2: string); overload; end; Well, yes, this is a possibility. It solves the problem of supporting all four combinations and it nicely puts related information into one unit. Still, we can do better. Operators to the rescue! I’m quite happy with the Create approach for providing an information triplet. it is the other variant – the one with just a single URL parameter – that I would like to simplify. I would just like to provide a simple string when the URL is in one piece. To support that, we only have to add an Implicit operator which converts a string into a TURL record. (Another one converting TURL into a string is also helpful as it simplifies the use of TURL inside the TConnector class.) Here is full implementation for TURL: TURL = record strict private FUrl: string; public constructor Create(const proto, host, path: string); class operator Implicit(const url: string): TURL; class operator Implicit(const url: TURL): string; end; constructor TURL.Create(const proto, host, path: string); begin FURL := proto + '://' + host + '/' + path; end; class operator TURL.Implicit(const url: string): TURL; begin Result.FURL := url; end; class operator TURL.Implicit(const url: TURL): string; begin Result := url.FURL; end; Simple, isn’t it? The implementation uses the fact that TConnector has no need to access separate URL components. It is quite happy with the concatenated version, created in the TURL.Create. This allows us to provide parameters in a way that is – at least for me – a good compromise. It allows for a (relatively) simple use and the implementation is also (relatively) simple: conn2 := TConnector2.Create; try conn2.SetupBridge('http://www.thedelphigeek.com/index.html', 'http://bad.horse/'); conn2.SetupBridge('http://www.thedelphigeek.com/index.html', TURL.Create('http', 'bad.horse', '')); conn2.SetupBridge(TURL.Create('http', 'www.thedelphigeek.com', 'index.html'), TURL.Create('http', 'bad.horse', '')); // this works as expected: conn2.SetupBridge(TURL.Create('http', 'www.thedelphigeek.com', 'index.html'), 'http://bad.horse/'); finally FreeAndNil(conn2); end; The output from the program shows that everything is OK now:
  3. I like to write code without warnings and hints issued by the compiler. Today I encountered the following warning: program TestCaseW1010; {$APPTYPE CONSOLE} type TPerson = class Name: string; function ToString(Quote: boolean): string; overload; end; function TPerson.ToString(Quote: boolean): string; begin if Quote then Result := '"' + Name + '"' else Result := Name end; var Person: TPerson; begin Person := TPerson.Create; Person.Name := 'John'; Writeln(Person.ToString); // --> TPerson Writeln(Person.ToString(False)); // --> John Writeln(Person.ToString(True)); // --> "John" Readln; Person.Free; end. The compiler shows W1010 Method 'ToString' hides virtual method of base type 'TObject'. In fact, he does not. Is it a false positive warning, or is it something wrong with my code?
  4. A while ago I did some development using DelphiAST. I've since added a symbol table and a writer that writes out Delphi code. This allows me to do something really cool: read in Delphi(like) code and output transformed code. One of the things this allows is new operators like +=, /= etc. It also allows for the new for var i: integer:= 0 to 10 do ... syntax to be ported. I simply read in the new syntax and output the old, taking care to resolve any name clashes. Obviously this also requires me to rewrite the syntax highlighter, which I have not done so far, because this is a bit harder, still I think it would make an interesting project and help with the adaptation of the new language features. Is there documentation regarding the new language features in Rio? I cannot seem to find more than a few still shots from David's presentation?