Profile photo of marc

by marc

An Update on RemObjects Silver

March 31, 2015 in "Silver"

Hi.

I wanted to take a brief moment to give you an update on the status of Silver, our Swift compiler for .NET, Java/Android and Cocoa.

First of all, thank you again for trying out Silver. Interest in the compiler has been tremendous, with over 1600 people using the beta now. We could not be more thrilled.

Timeline

Things have really been coming together over the last weeks and the past few weekly beta drops – the beta we shipped last Friday (build .1727) is really solid.

We’re ready for the next step, so this coming week we are planning to promote the current codebase to our lockdown/gamma branches. That means we’ll start preparing to ship based on this codebase, allowing only the most critical and stability-focused fixes to go into the branch between now and when we officially ship “Elements 8.1” (which will include updates to Oxygene and C#, as well as the first official “RTM” release of Silver).

We expect the next build you see to be a Gamma build, and hope to have the “master” Elements 8.1 release with you and all Elements users before the end of April.

Of course, even as we lock down for 8.1, work is already ongoing for the next releases as well, and we’ll make beta versions of that available, too.

Help Us Make Silver a Reality

If you like Silver and what we are doing, and would like to support our efforts, I would like to once again ask you to consider helping us out with a small (or large, if you prefer) financial contribution via the links here, or by purchasing a full Elements 8 license (which will give you all the great features of Silver using the C# and Oxygene languages, as well) here.

Silver is and will be free to use at no charge by everybody – that includes the command line compiler and the full IDE experience in Visual Studio and Fire. Your contributions help us finance the continued development of Silver and all of Elements, and enable us to make it available for free to everybody who wants it.

Thanx Again!

So, thank you again for your interest in Silver, and for taking the time to read this. We really appreciate your thoughts and feedback on Silver (and all of Elements), so please do not hesitate to contact us and let us now, via email or on the Talk forums.

Like you, we are very much looking forward to and excited about the upcoming release.

Yours,
marc hoffman
Chief Architect,
RemObjects Software

Profile photo of marc

by marc

Oxygene for Delphi Developers: New Features

January 28, 2015 in Elements, Oxygene

Oxygene has come so far from where Delphi left the Pascal language when it stopped innovating in the late ’90s that it’s hard to provide a simple and concise overview of what’s “new” in Oxygene for Delphi developers – there’s just so much.

This topic will try to provide brief sections on most of the major improvements and new language features that Oxygene provides, covering them with a brief introduction and then linking off to the main language documentation where you can find more details.

Pretty much all of these features, with the one exception of Generics, will be new to you, whether you are coming from Delphi 7 or a more recent Delphi version such as XE7, because the Delphi language really hasn’t changed much over the past 15 years.

Types

While pretty much all code in Oxygene lives inside types, this first section looks at new kinds of types that Oxygene introduces (such as tuples and sequences), and fundamentally new things you can do with types (such as nullability). Let’s get started.

Sequences

Sequences are a special type that exist on a similar level to Arrays, and can also be thought of as a collection of elements.

Different from arrays, sequences do not imply a specific form of data storage, but can represent any collection of elements that is accessible in a specific order. This could be an array (and as a matter of fact, all arrays can be treated as a sequence) or a different data store.

One major advantage of working with data via sequences is that your code can start to work on the first items of a sequence before the entire sequence has been generated. Your code might even stop working the sequence at some point, and the remainder of it never will be generated. This allows for some pretty powerful use. For example, you can query a large database table, and have rows fetched as you need them. You could even have an infinite sequence that generates all the digits of Pi, and choose to process only the first 10,000.

Sequences are defined with the sequence of keyword combo, parallel to arrays:

var lCustomers: sequence of Customer;

Sequences can be looped over with the regular for each loops that recent versions of Delphi have also introduced, and they also work great with LINQ and Oxygene’s from expression syntax for LINQ.

Aside from many APIs in the frameworks that already expose sequences, the Iterators and For Loop Expressions features discussed below help you define your own sequences in Oxygene.

Tuples

Tuples are the second new kind of “container” type introduced by Oxygene. You can think of a tuples as a group of two or more strongly typed variables that can be used and passed around in combination – for example passed into or returned from a method.

Each member of a tuple can have a different, well-defined type (for example, you can have a tuple of a number and a string), but different than a record, members of a tuple have no individual names. Commonly, tuples are used in a more light-weight fashion, in places where declaring an explicit record type somewhere else would seem overkill.

Types are defined with the tuple of keyword combo:

var lError: tuple of (Integer, String) := (404, "Page not found")

You can access individual members of a tuple using their numeric index, such as lError.0. You can also assign tuples back into individual variables by using a tuple literal on the left side of an assignment:

(lCode, lMessage) := WebRequest.GetError();

Future Types

A Future Type is variant of a type that promises to have a value at a later time, but that value might not be calculated or obtained yet, and may be derived either asynchronously in the background, or the first time the future’s value is accessed.

Any ordinary type known in Oxygene can be used as future by prefixing its type name with the future keyword:

var lCount: future Integer := lSomeSequence.Count; // the count of a sequence might be costly to determine

An ordinary future as in the example above will be evaluated the first time the value is accessed. All future access to the variable will use that same value. In essence, the future enables lCount to be referred to multiple times, but ensures it won’t actually be calculated until (and unless) it is actually accessed. Within any subsequent code, lCount can be used just as if it were an ordinary Integer, so it could for example be used in arithmetic expressions such as lCount/4+lCount.

Futures really shine when used in combination with async expressions, as covered below. A future initialized with an asynchronous expression will start calculating its value in the background automatically, so it might already be available when first accessed. As such, futures really help writing parallelized code that can take advantage of multi-core CPUs, with very little work.

Anonymous Classes

Anonymous Classes provide a syntax to quickly define and instantiate a simple class – commonly containing only data, but no code – from inside the code that will use it. Anonymous classes are not often used on their own, but they really shine when used in combination with Sequences and LINQ, as they enable you to filter down or combine data from sequences into new objects on the fly.

For example, as you are processing a lot of Customers and their Orders, you might want to generate a new list that contains each Customer and their total order volume, and then loop over that list. Anonymous classes make that easy without having to clumsily define a class for this. In particular, the select clause of LINQ from expressions will commonly define new anonymous classes.

Anonymous classes are defined using the new class keyword combo:

var lCustomerData := new class(CustomerID: lCustomerID, OrderVolume: lOrders.Sum);

Anonymous Interfaces

Anonymous Interfaces are very similar to anonymous classes, and are used to define a new class inline that satisfies (i.e. implements) a given interface. This is commonly used on the Java and Android platform, where rather than Delphi- or .NET-style Events, controls usually are assigned a delegate object that implements a given interface in order to receive callbacks when events happen – such as to react to the click of a button.

Anonymous interfaces allow you define such a class inline and implement one or more handler methods without having to implement the interface on the containing class (which can be awkward if you need to provide different handlers to different controls – for example two different click events on two different buttons).

You can think of anonymous interfaces as an extension or a more sophisticated version of Anonymous Methods. In fact, an anonymous method is considered the same as an anonymous interface with just one method.

Anonymous classes are defined using the new interface keyword combo:

fButton.delegate := new interface(OnClick := method begin
// handle the click here
end);

Partial Types

The Partial Types feature allows the definition of a Class or Record to be split across two or more source files. This is mainly used for three different types of scenarios:

  • Complex or very large classes can be split up to keep the individual code files more manageable.
  • Classes that are shared across platforms (for example via Shared Projects can have one part that’s shared, and another that provides platform-specific logic, without needing excessive $IFDEFing.
  • Some UI frameworks, such as WinForms and WPF will use one part for user code, while a second part is maintained by the visual designer or build tool chain.

Nullability

In Oxygene, like Delphi, simple value types that are stored on the stack will always have a value (a default of 0, if not otherwise initialized), while reference types (mostly Class) that are stored on the heap will be nil unless initialized.

Oxygene, however, provides a way to override this. A variable, field or parameter of value type can be marked as nullable type to indicate that it will default to (and can be assigned) nil. Similarly, a variable of reference type can be marked as not nullable, causing the compiler to enforce it to always be assigned a valid value and never be nil.

Most interestingly, and unique to Oxygene and the other Elements languages, nullable value types can be used in code, including arithmetic expressions, just as their regular counterparts. The Nullability will filter through, so that any expression using a nullable type will in turn also be nullable – and in true tertiary boolean logic, an actual nil value in an arithmetic expression will turn the whole expression nil.

var x := nullable Int; // nil
var y := 5;
var z := 10*x+y; //z will be nullable, and nil

You can read more about nullability here.

Mapped Types

Mapped type are a unique feature of the Elements compiler. They let you create compatibility wrappers for types without ending up with classes that contain the real type. The wrappers will be eliminated by the compiler and rewritten to use the type the mapping maps to.

When working with Oxygene, you will most commonly use mapped types (for example as provided by the Sugar cross-platform library). Using mapped types is seamless, and they behave just like regular non-mapped types.

You will not often need to implement mapped types yourself, but for when you do, Oxygene – like RemObjects C# and Swift – provides a syntax for implementing mapped types when needed, with the mapped keyword.

Please refer to the Mapped Types topic in the Language Concepts section for more details.

Type Members

That covers actual types, and as you see, Oxygene has quite a lot to offer. Next, let’s have a look at what you can do within those types (and in particular, Class or Record. It’s also worth mentioning that in Oxygene, Records are elevated to be pretty much as powerful as classes: In addition to fields, they can contain properties and methods, just like their siblings.

Pretty much the only difference between the two kinds of types is that classes are heap based – they get created in memory as needed, and variables refer to their memory location. More than one variable can point to the same class instance, and you can pass class instances all around your program. Records are stack based and value types. Two variables of record type will always point to unique copies of the record, and passing a record as parameter or assigning it to a second field or variable will create a copy of its data.

Advanced Fields

Fields in classes and records work and behave pretty much as you know them from Delphi. The only new feature for fields is that they can be marked with the readonly directive, which indicates that they can only be written from the Constructor or via an initializer, but are then immutable.

Fields can also be initialized in line, and when they are, their type can be omitted if it can be inferred from the initial value.

fCount := 5; readonly; // fCount will be an Integer

Advanced Properties

Just like fields, Properties in principle work as in Delphi, but as mentioned above are also supported in Records, not just Classes.

That said, Oxygene vastly expands the syntax for declaring properties, making them a lot more convenient to define and work with. All of these features are covered in detail in the Properties section.

  • Like fields, properties can me marked readonly.
  • Like fields, properties can be initialized inline.
  • Properties can be declared without read and write clause, and will automatically be backed by an implicitly created field.
  • Properties themselves can be marked virtual and be overridden, which is cleaner than relying on virtual getters/setters as Delphi does.
  • Properties can be defined in Interfaces.
  • Properties can define different visibility for the getter and setter, for example letting you declare a property that is public readable but only private or protected writable, which can be very powerful.
  • Properties can be marked as locked to synchronize their access to be thread-safe.
  • Properties can be marked to generate Notifications when they change, via the notify directive.
  • Properties can be marked as lazy and have their initialization deferred until they are first accessed.
  • Properties can use more complex expressions than just a field or method name for their read and write statement.

Advanced Methods

Methods also work just as in Delphi, and are supported in Records as well, not just Classes. As mentioned in the Minor Differences topic, Oxygene introduces a new method keyword that we recommend to use for methods, instead of the old procedure and function keywords. It emphasizes the Object-Oriented nature of Oxygene, and deemphasizes the largely irrelevant difference of whether a method returns a value or not. But procedure and function still work as well, in Delphi Language Compatibility Mode.

But once again, Oxygene expands the syntax for declaring methods, all of which is covered in detail in the Methods section.

  • Like properties, methods can be marked as locked to synchronize their access to be thread-safe.
  • Methods can me marked as async to indicate that they will automatically execute in the background. async methods with a return value will return a Future.
  • Methods can me marked as empty if they are placeholders that perform no function. This saves creating an empty method body.
  • Methods can be marked as inline, and their logic will then be embedded into the calling code for performance optimization.

In Oxygene, methods can use a new “multi-part method name” syntax that embraces Cocoa naming conventions (but is available on all platforms, and for all three languages) and makes for more readable and expressive method calls. You can read more in the respective section in the Methods topic.

Methods can also define pre- and post-conditions to validate their arguments and their results, which is covered further down on this page and under Class Contracts.

Iterators

Iterators are a special kind of method that makes it easy to implement dynamically generated Sequences. Marked with the iterator directive, an iterator method can write regular linear code that can use the yield statement to add values to the sequence. yield works similar to exit in that it returns a value, except that the execution flow of the iterator method keeps going, because the returned value is just one of many that make up the final sequence.

Multi-Cast Events and Blocks

Oxygene introduces a new kind of member for classes and records: Events. While in Delphi events are essentially properties of a special type, and thus get no special syntax, events in Oxygene are fundamentally different and separate from regular properties, and are defined with the event keyword.

Events are multi-cast, meaning that more than one handler can be assigned to an event using the += operator that Oxygene introduces exclusively for events. When the event is triggered, all assigned handlers will be called.

Multi-cast Events are almost exclusively used on the .NET platform, since the Cocoa, Java and Android platforms have different default mechanisms to deal with this concept – such as the Anonymous Interfaces discussed earlier on Java, or more traditional delegate classes on Cocoa. But the Event syntax and infrastructure is nonetheless available on all three platforms, should you wish to use it.

Custom Operators

Finally, Oxygene allows you to define Custom Operators for your classes and records, allowing them to participate naturally in arithmetic expressions. For example, you can define the + operator for a record representing a Complex number or a Matrix, allowing code that consumes the new record (or class) to seamlessly add two values together.

You can read more in the Custom Operators section.

Statements

We’ve now covered both types and their members, so next, let’s take a look at what Oxygene lets you do inside those members, most particularly Methods-like members, in terms of the kinds of Statements you can write.

Inline vars and Type Inference

Most prominently, Oxygene does away with the need for an explicit var section at the top of each method where all the method’s local variables need to be declared.

Instead, Oxygene lets you declare variables throughout the flow of your method where they are needed, with the new var statement. This makes code easier to understand, as variables can be declared closer to where they are used, and even inside nested scopes, such as if blocks or Loops.

More importantly, the var statement supports type inference, so you can, for example, assign the result of a method call to a new local variable without restating (or even knowing) the exact type. Variables defined with inferred type will of course still be strongly typed.

Type Inference is of course especially important when working with Anonymous Classes discussed above, since these classes don’t even have a known type name that could be explicitly stated. Type inference is the only way to declare a variable holding such a type (or a Sequences of such types).

Infinite Loops

Mostly a curiosity but handy at times, Oxygene introduces a new loop type that runs indefinitely, with the loop keyword. A loop loop, also called an infinite loop, has no pre-determined exit condition and keeps running until it is broken out of with break or exit.

While not used often, loop does make for cleaner code and lets you avoid awkward and unintuitive while true or repeat until false loops.

Improved For Loops

for loops have also bee greatly expanded in Oxygene.

For one, Oxygene adds a new for each/in variation in addition to the trusted for/to loop. for each loops run over all members of a collection, Array or Sequences, without your code having to maintain an indexer manually. (More recent versions of Delphi have adopted this loop style as well, so you might already be familiar with it.)

for each loops also have two advanced syntaxes.

  • Via the index keyword, you can introduce a second loop variable that keeps track of the count of loop iterations, without you having to increment the variable yourself. Essentially, index gives you the best of both for each and for/to loops, in one.
  • Via the matching keyword, you can limit the loop to only execute for those members of a collection that are of a specific sub-type.

Currently on .NET only, both loop types can also be made to run multiple loop iterations in parallel on different threads, via the parallel keyword.

Exception handling

Exception Handling has been expanded over Delphi’s in two ways:

  • A single try block can be followed by both a finally block and one or more except blocks. There no longer is any need to nest two try blocks just to leverage both types of handler.
  • except blocks can be expanded using where clauses to further filter which exception a given block will catch, using criteria other than just the mere exception type.

Advanced Case Statements

Oxygene expands the case statement to be more flexible. case statements can work on strings (smartly using a hash table in the background for efficiently finding the proper case to execute). This not only saves code over needing to write multiple if/else if/else if statements, but is also faster.

The case statement can also execute different branches based on the type of its parameter, via the new case/type of syntax.

Refer to the case Statements topic for more details.

Locking

Similarly to the locked directive on Methods and Properties already mentioned above, the locking statement can protect a section of code against parallel execution on multiple threads, making it very easy to write code that is ready for parallelization. Via its parameter, the locking statement gives you flexibility for how granularly to synchronize execution – for example per instance, or globally.

Using

While Oxygene uses GC or ARC on all platforms and you do not usually need to worry about memory and object lifetime management, sometimes your code will interact with external resources (such as file or network handles) that do need to be released in a clean and timely fashion.

The using statement allows you to write a block of code that will run and make use of a specific object and automatically dispose of the object at the end. Essentially, using is a convenient way to encode a try/finally block that makes sure your object and external (“unmanaged”) resources get cleaned up.

Expressions

With statements out of the way, let’s look at some of the improved Expression types Oxygene provides.

Colon Operator

Small but immensely powerful, the Colon (:) Operator is a team favorite of all the features in Oxygene.

Delphi and Oxygene normally use the Dot (.) operator to access members such as Properties or Methods of a class reference. This is something so natural and so frequently done, we mostly don’t even think about this as a special expression.

When trying to access a member of a class reference that happens to be nil, an exception is raised. In Delphi, that is the dreaded Access Violation straight from the CPU, in Oxygene it’s a Null Reference Exception, often chummily called “NRE”.

NREs are great when they happen on truly broken code, as they report the failure in a clean and obvious manner. But oftentimes it would be nice to be able to write code that doesn’t need to care if an object is nil or not. That’s where the Colon (:) Operator comes in.

If you use : instead of . to call a member, Oxygene will automatically check whether the object you are trying to call into is valid or not. If the object is valid, the call will proceed as normal, same as with .. But if the object is nil, then rather than raising an NRE, Oxygene will just skip the call altogether and return nil as the result.

Consider this example:

var lKnownSiblings := lSomeObject.Parent:GetChildren();

This code will call the GetChildren method of the object from the Parent property of lSomeObject. But what if Parent is not assigned (for example because data is incomplete, or because lSomeObject is the root of the hierarchy)? Because the code uses :, the call to GetChildren will simply be omitted, and lKnownSiblings will be set to nil.

The Colon (:) Operator allows you to write code that’s simpler (often avoiding many nested if assigned(...) checks) and less error prone.

Double Boolean Comparisons

Double Boolean Comparisons allow you to compare three values in one step with a ternary operator – for example to check if a given value falls between two boundaries.

if 5 <= Count <= 10 then writeLn('between five and ten');

Lambda Expressions

[Lambda Expressions] provide a convenient shortcut syntax for writing short Anonymous Methods without the overhead of a full method/begin/end declaration. Lambda expressions are commonly used for single-statement methods, where they consist of an (optional) parameter list, the special -> operator, and the single statement. For example:

var lFives := lMyCollection.Where(x -> x.Value = 5); // filter list to items with value 5

Lambda expressions can be used anywhere anonymous methods can be used – for example as event handler assignments or as Block parameters to methods. One very common scenario, as shown in the example, is to use them with the LINQ query operators.

If Expressions

if expressions take the regular if statement and allow it to be used for expressions. As such, the if expression evaluates a condition, and then returns one value or the other.

var lLabel := if lList.Count = 1 then 'Item' else 'Items';

Case Expressions

Similar to if expressions, case allow the regular case statement syntax to be used as an expression to return a conditional value:

var lCountString := case lList.Count of
0: 'none';
1: 'one';
2: 'two';
else 'more than i can count';
end;

For Loop Expressions

You are probably seeing a pattern here. For Loop Expressions are the expression version of the regular for loop statement. Since a for loop, by its nature, can run for many iterations, the result of a for loop expression is a Sequences of values:

var lSomeEvenNumbers := for i := 1 to 100 yield i*2;

Similar to Iterators, for loop expressions use the yield keyword to add a value to the generated sequence. Also like iterators, the value of a for loop expression merely represents the functional logic for generating the sequence. The loop code does not actually run until the sequence is enumerated.

Async Expressions

async expressions allow a statement or an expression to be executed and evaluated asynchronously on a background thread, returning a Future Type.

Calling an async expression will return immediately, and execution will begin in the background (immediately, or once a free thread is available based on system resources).

Await Expressions (.NET)

Available on .NET only, the await expression construct can be used to “unwrap” otherwise asynchronous code so that future results can be dealt with in a linear fashion. Under the hood, await will break the method into different parts, scheduling them to be executed asynchronously once the awaited actions have been completed.

Please refer to the await Expressions topic for more details.

From (LINQ) Expressions

A huge topic on their own, from expressions provide a rather sophisticated sub-language that allows you to use an SQL-like syntax to work with Sequences of objects in a strongly-typed fashion. They form the basis of LINQ support.

var lFilteredData := from c in lCustomers
where c.Name.StartsWith('O') // filter by name
order by c.DateOfBirth // order by date
select c.Name, c.Address; // and return only two fields
// via a new anonymous class

Note: Although LINQ technology originated on .NET, Oxygene makes it and from expressions available on all platforms.

“is not” / “not in”

Oxygene expands the standard is type check operator and the in operator that checks for membership in a set to allow for more natural use with the not keyword.

“`
if not (x is Button) then … // traditional Delphi
if not (5 in MySet) then … // traditional Delphi

if x is not Button then … // Oxygene
if 5 not in MySet then … // Oxygene
“`

Class Contracts

Last but not least, Oxygene introduces a major language feature called Class Contracts that allows you to write self-testing code in a “Design-by-Contract” fashion.

Class Contracts consist of two syntax features:

  • Inside method implementations, you can add code to check for pre-conditions and post-conditions using the require and ensure keywords, as shown in the “Method Implementation Syntax” section of the Methods topic.

  • On a class (or record) level, you can define Invariants that are used to define a fixed state the type must fulfill at any given time. This makes it easy to detect bugs where any method or property setter leaves the type in an inconsistent state.

You can read more about these features in the Class Contracts topic.

 

This article originally appeared on our new Elements docs site at docs.elementscompiler.com. Check out our whole section for newcomers from Delphi at docs.elementscompiler.com/Oxygene/Delphi

Profile photo of Anton

by Anton

Little Things that make a difference. Part II. DA LINQ String Operations

January 5, 2015 in .NET, Data Abstract

One thing that DA LINQ lacked until recently was support of the string data comparison operations. This means that there was no easy way to properly express SQL statement like:

SELECT
  Id,
  Name
FROM
  dbo.Customers
WHERE
  Name > 'Alpha'

using DA LINQ. Even worse – a lot of .NET languages don’t support < or > operators with sting operands. This means that, for example, C# cannot compile code like:

bool r = "A" > "B";

Of course there are a lot of ways to compare strings in .NET, but to use them, you first have to load the data into the client app using DA LINQ and then filter that data locally using Linq2Objects. Obviously, an approach like this is not always feasible, especially on big datasets or slow network connections.

So a different way to express string comparison operations was needed. Data Abstract was recently expanded with a set of extension methods allowing to express string comparison operations in DA LINQ queries like for example:

var data = from x in dataAdapter.GetTable() where x.Name.IsGreaterThan("Alpha") select x;

These extension methods provide enough information for the internal magic of DA LINQ to construct proper SQL statements.

The full list of supported string comparison operations is available on the corresponding docs page at http://docs.dataabstract.com/API/NET/StringExtensions_Class/.

Notice that while a set of .NET methods is used to express string comparison operations, the actual comparisons are still performed by the database. This has two implications:

  1. This feature will work only if sting comparison operations are supported at database level.
  2. String comparison results depend on database server collation settings.

Happy New Year!

Profile photo of Anton

by Anton

Little Things that make a difference. Part I. Application Base (addendum)

December 19, 2014 in .NET, Visual Studio

In this short article, the server application template created in the previous article will be turned into a real Visual Studio template. Greater minds have already described the process in the MSDN article at http://msdn.microsoft.com/en-us/library/xkh1wxd8.aspx.

Some preparation work is needed before the project can be turned into a real application template.

First, edit the AssemblyInfo.cs file, so it will look like this:

using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;

//
// General Information about the assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with the assembly.
//
[assembly: AssemblyTitle("$projectname$")]
[assembly: AssemblyDescription("$projectname$")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("$registeredorganization$")]
[assembly: AssemblyProduct("$projectname$")]
[assembly: AssemblyCopyright("Copyright (c) $registeredorganization$ $year$")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]


[assembly: ComVisible(false)]

//
// The version information for the assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all values, or you can default the Revision and Build Numbers
// by using the '*' as shown below:

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

[assembly: NeutralResourcesLanguageAttribute("")]

In the ServerApplication.cs file, change the Application ID, Application Name and Service Name properties to:

protected override string Identifier
{
    get
    {
        return "$guid1$";
    }
}

protected override string ServiceName
{
    get
    {
        return "$projectname$ Service";
    }
}

protected override string ApplicationName
{
    get
    {
        return "$projectname$";
    }
}

Open the MainService.cs in the designer and set the ServiceName property to “$projectname$ Service“.

Open the ProjectInstaller.cs in the designer and set the ServiceName property of the ServiceInstaller component to “$projectname$ Service“, as well.

Then replace the namespace ServerTemplate string with namespace $safeprojectname$ project-wide.

Save all changed files and issue the menu command File -> Export Template. Export the project as a project template. Set the template name and description and press the Finish button.

Restart Visual Studio. The template you just created will be available in the Visual Studio project templates.

P.S.: If you really don’t want to follow all those boring steps, here is the download link for the template project. Download, unzip and open it in Visual Studio, then export it as a project template.

Profile photo of Anton

by Anton

Little Things that make a difference. Part I. Application Base

December 18, 2014 in .NET, Visual Studio

This is the first of a set of short articles related to different Data Abstract or SDK features that I feel are important and interesting. Some of them will be just minor improvement notifications, while others will highlight something that can be called a feature but is still way too specialized to be highlighted in a big article. This first article will be about the common application base class that can be used for RemObjects SDK and Data Abstract server applications.

RemObjects SDK contains the ApplicationServer class which provides base application startup infrastructure including Windows Service management and single instance checks.

The ApplicationServer class was designed to provide a common codebase and simplify development of RemObjects SDK and Data Abstract-based server applications. It provides the following features:

  • 3 application run modes – GUI mode (WinForms or WPF), command-line interface or Windows Service.
  • Windows Service management (installation/deinstallation).
  • Optional Single Instance check.
  • Extensible startup arguments parser. The ApplicationServer class provides an overridable method to handle command-line arguments not handled by the default arguments parser. It is also possible to use your own implementation of the command line arguments parser.
  • Single exception intercept point (useful for logging etc.).

By default, ApplicationServer-based applications recognize the following command-line arguments (not case-sensitive):

Parameters
Description
-I, /I, –INSTALL Install as a Windows Service
-U, /U, –UNINSTALL Uninstall a Windows Service
-Q, /Q, –QUIET Suppress messages on service installation and uninstallation
-C, /C, –COMMANDLINE Run in CLI mode
-D, /D, –DEBUG Request extended debug info (i.e. full stack traces)
-H, /H, -?, /? Show command-line arguments help message

There is no need to write any code to handle these actions.

Data Abstract project templates rely on the ApplicationServer class, but the RemObjects SDK ones are still old-fashioned Windows Forms applications. The next part of this article describes how to create a base application that can later be used as a seed for new server apps development.

  1. Create a new RemObjects SDK project named, say, ServerTemplate.
  2. Delete the ServerTemplateClient from the solution.
  3. Delete the Getting Started.html file from the ServerTemplate project.
  4. The next major steps are to provide network connectivity infrastructure, Windows Service stuff and to tie them all together using the ApplicationServer class.
    First, update the licensing.licx file with the following content (so there won’t be any need to adjust the licenses file for each server project).

    RemObjects.SDK.Server.IpTcpServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.IpSuperHttpServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.IpHttpServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.NamedPipeServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.LocalServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.HttpSysServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.HttpSysSuperHttpServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.SuperTcpServerChannel, RemObjects.SDK.Server
    RemObjects.SDK.Server.EventSinkManager, RemObjects.SDK.Server
    RemObjects.SDK.Server.MemoryMessageQueueManager, RemObjects.SDK.Server
    RemObjects.SDK.Server.MemorySessionManager, RemObjects.SDK.Server
    RemObjects.SDK.Server.OlympiaMessageQueueManager, RemObjects.SDK.Server
    RemObjects.SDK.Server.OlympiaServerSessionManager, RemObjects.SDK.Server
    
  5. The next step is to create a component that will perform the networking operations. Unfortunately, it is not feasible to use the components already generated by the project template, as they are placed on a Windows Form. So add a new Component Class project item and set its name to Engine. Open the component and add the IpHttpServerChannel, BinMessage and MemorySessionManager components to the designer pane. Register the newly added BinMessage component in the IpHttpServerChannel.Dispatchers collection.

    Also, add the following methods and properties to the Engine.cs code:

    public void Start()
    {
        this.serverChannel.Activate();
    }
    
    public void Stop()
    {
        this.serverChannel.Deactivate();
    }
    
    public bool IsActive
    {
        get
        {
            return this.serverChannel.Active;
        }
    }
    
  6. Now create the Windows Service definition and infrastructure it needs. Add a new Windows Service item to the project and set its name to MainService. Open the code-behind file of the newly added service and set its code to:
    partial class MainService : ServiceBase
    {
        private Engine _engine;
    
        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
            this._engine = new Engine();
            this._engine.Start();
        }
    
        protected override void OnStop()
        {
            base.OnStop();
            this._engine.Stop();
            this._engine.Dispose();
            this._engine = null;
        }
    
        protected override void OnPause()
        {
            base.OnPause();
            this._engine.Stop();
        }
    
        protected override void OnContinue()
        {
            base.OnContinue();
            this._engine.Start();
        }
    }
    

    The code above is quite simple. It handles the service state change events and either creates and opens the server channel or closes it and disposes the corresponding components.

  7. Now open the service in design mode again and right-click the designer pane. In the context menu, choose the Add Installer item. This command will automatically add a service installer instance that encapsulates the WinAPI calls needed to install or uninstall a Windows Service.

    At this point, the ServerTemplate project has almost all code and components needed to work as a Windows Service.

  8. Delete the Main.cs form present in the ServerTemplate project and add a new Windows Form to the project named MainForm. Add the following code to its code-behind file:

    public partial class MainForm : Form
    {
        private Engine _engine;
    
        public MainForm()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();
    
            this.FormClosed += OnFormClosed;
            this.StartServer();
        }
    
        private void StartServer()
        {
            if (this.IsServerActive)
            {
                this.StopServer();
            }
            this._engine = new Engine();
            this._engine.Start();
        }
    
        private void StopServer()
        {
            if (this.IsServerActive)
            {
                this._engine.Dispose();
                this._engine = null;
            }
        }
    
        // Properties
        public bool IsServerActive
        {
            get
            {
                return ((this._engine != null) && this._engine.IsActive);
            }
        }
    
        private void OnFormClosed(object sender, FormClosedEventArgs e)
        {
            this.StopServer();
        }
    }
    
  9. The next step is to tie all these components together using the ApplicationServer class. Add the following class to the ServerTemplate project:
    using System;
    using System.ServiceProcess;
    using System.Windows.Forms;
    
    namespace ServerTemplate
    {
        sealed class ServerApplication : RemObjects.SDK.Server.ApplicationServer
        {
            private Engine _consoleEngine;
    
            protected override String Identifier
            {
                get
                {
                    return "2a42e444-5b2c-4f5c-b73a-dd1cab801c0a" ;
                }
            }
    
            protected override String ServiceName
            {
                get
                {
                    return "SimpleProject Service";
                }
            }
    
            protected override String ApplicationName
            {
                get
                {
                    return "SimpleProject";
                }
            }
    
            protected override void RunAsConsoleApplication()
            {
                this._consoleEngine = new Engine();
                this._consoleEngine.Start();
            }
    
            protected override void ShutdownAsConsoleApplication()
            {
                this._consoleEngine.Stop();
                this._consoleEngine.Dispose();
            }
    
            protected override void RunAsWindowsService()
            {
                ServiceBase.Run(new MainService());
            }
    
            protected override void RunAsWindowsApplication()
            {
                Application.EnableVisualStyles();
                Application.Run(new MainForm());
            }
        }
    }
    
  10. And as the very last step change the application entry point code in the Program.cs file to:
    using System;
    
    namespace ServerTemplate
    {
        static class Program
        {
            [STAThread]
            static void Main(string[] args)
            {
                new ServerApplication().Run(args);
            }
        }
    }
    

And that’s it: The server application project template. Applications created using this template can be run as Windows Forms apps, Windows Services or Linux daemons and are able to install themselves as Windows Services.

If you really want a quick result but don’t want to go over all the steps, here is the download link for the project created during this article: ServerTemplate

So far the only way to use this project template is to copy it to a new place when a new SDK server app is needed. In the next article, this application will be turned into a real Visual Studio project template.

Profile photo of marc

by marc

Staring into the Fire: Code Completion

September 8, 2014 in Fire

This post is part of a series in which I want to take a closer look at some of the features and functionality in Fire, our new IDE for the Mac. The topic for today is Code Completion.

Code completion, also called IntelliSense in Visual Studio parlance, is a crucial part of writing code these days. Instead of reading docs or knowing types and their members by heart, we rely on Code Completion to let us know and discover what APIs are there for us to use. And gone are the days of trying to save keystrokes by making names easy to type — because CC can help us type complex names, easily.

Of course Fire comes with state-of-the-art Code Completion in its code editor, driven by the same back-end engine that also provides CC data for our languages in Visual Studio. But while the content is the same, Fire takes the CC user interface to the next level, as we have really put a lot of thought into how we can improve the general experience.

In Fire, Code Completion will automatically activate as you type, wherever sensible. So you don’t need to think about it much, and it will automatically be there to help you, should you need it. Of course you can also manually invoke CC at the current cursor location, if so desired. You can either press Escape (which is the Mac default for this), or — if you’re still used to Visual Studio, and maybe switching a lot between the two IDEs — you can use Cmd-Space (after changing the global Spotlight shortcut, which you probably already did to use that combo on your VM, anyways).

CC is fast, but sometimes even the tiniest of interruptions can be annoying, so CC in Fire is completely asynchronous. Even while CC gathers info to show you, you can keep typing, or cursor elsewhere. If you type more of the current identifier, CC will adjust as you type to narrow your search. If you type or move away from the current identifier, CC will close (or never show, if you’re a really fast typer ;).

The CC “Soft Selection”

As Code Completion gets activated, you will notice that Fire will add a soft highlight to the current “token” that it considers relevant. This is a helpful indicator as to what part of your code will be replaced should you accept an item from the CC list.

If you use Visual Studio, you might have (consciously or subconsciously) noticed that sometimes when you select an item from CC, VS will replace the full token you are on, and other times, it inserts the new text in front of the existing text. If you’re like me, on more than one occasion you’ll have been annoyed that it did the opposite of what you wanted or expected. Fire’s visual indicator helps with that. For example, if you start typing at the very front of a token, chances are that you are adding a new token in front and don’t want to replace what’s already there, so CC will not absorb the text behind the cursor:

But if you invoke CC in the middle of an identifier, chances are you want to replace the whole identifier, so Fire’s UI will reflect that:

Not only does the “soft selection” show you what to expect, but Fire is also smart about picking the right “mode” for CC, depending on the context it finds itself in.

Partial CC

Fire’s CC also has a nifty way that helps you type complex names. Take the following example of very common Cocoa code:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_NORMAL, …)

That is a huge pain to type, even with CC, because each the three identifiers starts with “dispatch_”, and there’s a huge list of those. So you end up either typing most of the names manually or doing a lot of scrolling through the CC list. Not anymore!

In Fire, when you press Tab or underscore (_), CC will automatically advance to the next underscore in the current item (or to the next item with an underscore. So for example, if you just type dis_g_g_q(, CC will smartly navigate you through the list so that you end up with dispatch_get_global_queue(|):

Similarly, Tab also jumps ahead between parts of PascalCased names. So it’s just NSFil<Tab>Ma<Tab> and you have NSFileManager.

The Devil’s in the Details

There are other small details that streamline the CC experience. When CC gets invoked and there’s no current token to soft-select yet (the most common case when you’re starting a new identifier), Fire will show a small “sliver” of a soft selection to the right of the cursor to show you CC is coming:

If you accept CC for a method by typing (, Fire will automatically insert the pair of parenthesis and put the cursor between them — if you accept CC with a different key, for example with space or enter, it will not.

Of course CC also handles multi-part method names in Oxygene, C# and Silver (even if they look like named parameters in the latter) — inserting the full method signature for you, and giving you “jump points” to let you tab from one parameter to the next:

If you ignore CC and “type through”, CC will smartly do the right thing when you come to the end of the identifier. For example, it will adjust the case of what you typed to the proper item in CC. But not if the version you typed would also be valid, as in the case below (which of course only happens in case sensitive languages, i.e. C# and Silver):

When you start typing in the middle of an existing identifier, CC will not drop down automatically. Chances are you’re trying to fix a typo or otherwise know what you’re doing, and our use testing showed that the CC dropdown just gets in the way. (Of course you can still invoke CC manually via Escape for that location — it will then cover the entire identifier.)

Just like these, there are lots of little tweaks and and “special cases” — some even language-specific — that fine-tune CC to behave as you’d want it to and not get in the way. Most of them being cases that you won’t actually notice — except by lack of being annoyed ;).

Summary

This post gave you a quick look at what Code Completion is like in Fire. Code Completion is implemented as part of Fire’s Code Editor, which we have written from scratch to give you the best possible code editing experience. I’ll talk more about the Code Editor in general in a future post.

Stay tuned, check out Fire, and make sure to let us know what you think!

—marc

Profile photo of Alex

by Alex

Strong Typed Rows in the DataAbstract for Cocoa

September 1, 2014 in Uncategorized

Challenge

In DataAbstract for Cocoa, you can retrieve the values for a particular table field using the KVC approach, where the field name is passed as a string key:

DADataTableRow *row = [[self table] rowAtIndex:idx];
NSString *name = [row valueForKey:@"ClientName"];

Later, with help of the new indexing syntax for arrays and dictionaries, this code can be rewritten in a more simple manner:

DADataTableRow *row = self.table.rows[idx];
NSString *name = row[@"ClientName"];

But there is one flaw to that approach – the field name is passed as a string constant and thus can’t be checked in design time or selected in the code completion system.
The user still has to work with DADataTabeRow instances, where data is represented by the dictionary, rather than by business objects.

Solution

With the help of some “Magic” in Objective-C, we can now offer another approach for getting values for a particular column in a row.
You can just operate with a particular field in the table row as with a usual property.
This means that you can call any property in a row instance like this:

id fieldValue = [self.dataTable.rows[idx] MyFieldName];

If there is no such field in the table, you will get a proper exception, otherwise you will get its value.

It would also be great though if we could choose available fields using the Code Completion system inside the IDE.
This would simplify the code and allow to avoid various possible mistakes in specifying field names when working with data of the row.

And the answer is yes, we can do that.
All we need to do is to represent the available table fields as properties of a special protocol (interface) that the row can support.

This approach can be used in two ways:
The most simple way is to just generate protocols ad later cast the row instance to the row protocol. For example:

 
// Protocol
 
@protocol DepsTableRow_Protocol <NSObject>
@property (strong) NSString *DepName;
@property (strong) NSNumber *DepId;
@property (strong) NSString *DepPhone;
@end
 
 
// Code for obtaining data 
 
id row = self.dataTable.rows[0];
id<DepsTableRow_Protocol> typedRow = row;
NSNumber *depId = [typedRow DepId];
NSString *depName = [typedRow DepName];
NSString *depPhone = typedRow.DepName;// you also can use dot(.) for accessing field property
 
NSLog(@"%@(%@): Phone:%@:", depName, depId, depPhone);

Another approach is to provide a special row class for the particular table.
This class must be inherited from the base DADataTableRow class, but in addition, it can expose different properties:

//Protocol:
@protocol DepsTableRow_Protocol <NSObject>
@property (strong) NSString *DepName;
@property (strong) NSNumber *DepId;
@property (strong) NSString *DepPhone;
@end
 
// Custom row class 
@interface DepsTableRow : DADataTableRow <DepsTableRow_Protocol>
// you don't need to implement DepsTableRow_Protocol for declaring its properties
@end
 
// Code for obtaining data:
// First we need to register our custom row class for the particular table
// It should be done once per application start 
// The init method of the DataAccess module is usually a good place for doing that
[DADataTable registerRowClass:[DepsTableRow class] forTableName:@"Deps"];
 
// then later each row in the table rows array is the instance of our custom row
DepsTableRow *typedRow = self.dataTable.rows[0];
NSNumber *depId = [typedRow DepId];
NSString *depName = [typedRow DepName];
NSString *depPhone = typedRow.DepName; // You can use a dot(.) to access fields as properties
 
NSLog(@"%@(%@): Phone:%@:", depName, depId, depPhone);

Supporting Strong Typed Rows in Nougat

The same approaches are also available for Nougat projects and Oxygene:

// Protocol
DepsTableRow_Protocol= public interface
    property DepName: strong NSString read write;
    property DepId: strong NSNumber read write;
    property DepPhone: strong NSString read write;
end;
 
// Code for obtaining data 
var row: id := self.dataTable.rows[0];
var typedRow : DepsTableRow_Protocol :=  duck<DepsTableRow_Protocol>(row);
 
var depId := typedRow.DepId;
var depName := typedRow.DepName;
var depPhone := typedRow.DepPhone;
 
NSLog("%@(%@): Phone:%@:", depName, depId, depPhone);

and for RemObjects C# (Hydrogene):

// Protocol
public interface DepsTableRow_Protocol
{
    __strong NSString DepName { get; set; } 
    __strong NSNumber DepId { get; set; }
    __strong NSString DepPhone { get; set; }
}
 
// Code for obtaining data 
id row = self.dataTable.rows[0];
DepsTableRow_Protocol typedRow = duck<DepsTableRow_Protocol>(row);
 
NSNumber depId = typedRow.DepId;
NSString depName = typedRow.DepName;
NSString depPhone = typedRow.DepPhone;
 
NSLog("%@(%@): Phone:%@:", depName, depId, depPhone);

Generating protocols

The one remaining question is how to get those row protocols?

For Nougat projects created in MS Visual Studio, these protocols will be generated automatically by the New Project Wizard.
You can also update/regenerate these protocols any time you want – just run the wizard by clicking Create Table Definition Classes in the Solution Explorer window. TableDefinitions Wizard

For Xcode projects, you can generate the protocols directly from the schema node inside the Relativity Server in the Server Explorer for Cocoa tool. It allows to generate Objective-C, Oxygene and RemObjects C# protocols for Nougat projects. TableDefinitions Generator

Samples

Take a look at the StrongTypedRows (iOS) samples written in Nougat, Oxygene and RemObjects C#. We are providing them with the DataAbstract for Cocoa package.

Thanks for reading!

Profile photo of Alex

by Alex

Using DataAbstract and RemObject SDK for Cocoa libraries in Swift

September 1, 2014 in Cocoa, Uncategorized

As you probably already know, Apple recently announced a new programming language called Swift, a new and fresh look at programming for the Mac.
The main and obvious purpose of Swift is to replace Objective-C in the future.

To develop for the Mac, RemObject Software offers two products, DataAbstract for Cocoa and RemObject SDK for Cocoa.
These products are designed using native Apple technologies and are written in Objective-C.
They are available as frameworks and as static libraries.

This brings us to the important question: Can I use existing libraries written in Objective-C in a program written in Swift?

The answer to that question is yes.

In order to access classes from Objective-C libraries from Swift, you need to create a so-called Bridging Header File and name it according to your product module name followed by -Bridging-Header.h.
Then you need to edit this file to expose your Objective-C code to your Swift code.
Just import every Objective-C header you want to expose to Swift. In our case, this will be the root Data Abstract header:

//
//  DAWithSwift-Bridging-Header.h
//
 
#import <DataAbstract/DataAbstract.h>

Then go to the project settings and locate the “Swift Compiler – Code Generation” section at the “Build Settings” tab, where you need to specify the bridge header file for the “Objective-C Bridging Header” build setting.
The path must go directly to the file itself, not to the directory it’s in.
The path should be relative to your project, similar to the way your Info.plist path is specified in Build Settings.
For example:

DAWithSwift/DAWithSwift-Bridging-Header.h

Also, do not forget to set the other build options to allow your application to locate and link it with the RemObjects libraries:

Library Search Path = "/Developer/RemObjects Software/Bin/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"
Other Linker Flags = -ObjC -all_load -lxml2 -lDataAbstract

And that’s it, now all public Objective-C headers listed in this bridging header file will be visible to Swift.

The Objective-C functionality will be available in any Swift file within that project automatically, without any import statements.
You can now use DA/RO classes with the same Swift syntax that you can use with system classes.

 
//SWIFT
 
// Set up rda and server access
var dataAdapter: DARemoteDataAdapter
let url: NSURL = NSURL(string:"http://localhost:7099/bin")
self.dataAdapter = DARemoteDataAdapter(targetURL:url)
dataAdapter.dataService.serviceName = "DataService"
println("dataAdapter: \(dataAdapter.dataService.channel.targetURL)")

At the moment, most of Swift is covered by the Apple NDA until it is released, but after that we are going to simplify even those steps above.

Thanks for reading!

Profile photo of marc

by marc

Staring into the Fire: The Build Process

August 6, 2014 in Fire

This post is part of a series in which I want to take a closer look at some of the features and functionality in Fire, our new IDE for the Mac.

Fire is designed to be light-weight and “get out of your way”, and one of the parts where this shines thru is when you build. Compiling your project is a frequent task in your day.to-day work, and an essential part of any development environment.

You usually start a build by either hitting Cmd-B (to just build) or Cmd-R (to build, and then run), and when you do, the build system goes off to do its thing in the background, but aside from that, nothing much changes. There’s no silly modal dialog telling you the IDE is building, or the like. After all, building is something that happens passively and once a build is fired off, there isn’t much you can do about it (although actually, that’s not quite true, more on that later on), so the IDE might as well just let you keep focusing on your code.

Building

So as Fire goes off to build, focus stays on the code editor (or wherever else it was before you hit Cmd-B), and you can just keep on coding. There’s only a couple of small indicators that a build is running: For one, the jump bar at the top of the window turns blue as the build runs and cycles thru the build tasks in the status area on the right. And if you’re in full screen “focus mode” with the code editor covering your entire screen, that’s all you see.

The application icon in the Dock also turns blue — which is handy if you actually are switching away from Fire while you wait for a build, as you can now see the build status and success/failure with one glance at the Dock or the Cmd-Tab app switcher.

When the build finishes, jump bar and app icon either go back to normal (if all went well), or they turn red (if one or more projects failed to build). That, and an optional notification center message, is your only indication that the build failed — again, nothing happens that pulls you out of the flow, as chances are you just went right on coding wile the build was happening.

Messages

Fire has no dedicated “Error Messages” view that pops up when a build fails. Instead, build messages are integrated with Fire’s regular navigation infrastructure: They fill into the jump bar at the top, for manual selection/browsing, and they also show inline in the text editor. Chances are, new build errors are happening right in the code you are currently working on, so having them show up where you are already looking at — the code window — is the best place for them, and in most cases, you need little else to find out what went wrong.

When you do, your favorite new keyboard shortcut will be Option-Cmd-M (or the Messages|Show First Message) menu, which — as the name indicates — jumps right to the first message generated by the build. If there have been errors, it brings you to the first error that was encountered; if there were none, it brings you to the first warning or hint, if any.

Of course, you can also look at the jump bar, which shows you all build messages under the Build Log node, and select a message from there.

Once you navigated to a message, you can use the Control-Command-Up and Down keyboard shortcuts (or Project|Navigation|Up/Down in the menu) to cycle between messages and jump from one to the other.

If you are the kind of person who does want to get distracted when building, Fire has a few options for you in the Preferences dialog, under Build & Debug: For one, you can choose to have Fire bring forward the build log either when a build starts, or when it fails. This option can be helpful in certain situations (for example when you are “debugging the build”, i.e. when you’re in a development mode where you’re looking at build issues and expect to look at the build log a lot), but I really recommend not turning it on for day-to-day work. You can also optionally have Fire jump to the first error if a build fails (which is how many IDEs behave, such as Delphi and Visual Studio — but again, I recommend against it, for the reasons outlined above).

Another cool thing you can do with build messages is copying code along with its messages to the clipboard. This is really helpful when you want to share a build problem with team-mates for help, or when you want to post questions about a build error somewhere. Simply select the range of code you’re interested in and press Option-Command-C (or Edit|Copy w/ Build Messages from the menu), and Fire will copy the code as you expected — but it’ll add any error messages to the code as well (prefixed by a // comment delimiter, so that the copied code remains valid). Really handy.

Don’t Stop Me Now.

Sometimes you press Cmd-B to start a build, and immediately regret it. This happens to me all the time: I write some code, press “build” to see if it’s any good, and the second I do, I spot that missing semicolon, that typo, or something else that’s silly. In Visual Studio, I’d now sit there and wait for the build to finish, just to go again, and that always has been a huge frustration to me. Not so in Fire.

There’s two things you can do when you started a build that you know will be no good. For one, you can press Cmd-. (or Project|Stop in the menu) and cancel the build. Bam, it’s stopped. More interestingly, if you just fixed that silly typo and want to build again, you can just hit Cmd-B again, and it will automatically cancel the current build and start fresh.

This might seem like a small thing, but I think you’ll find it a game changer in how you build — especially if you’re working on larger projects that take a few seconds to build. For example, a build of Fire takes between 10 and 30 seconds, depending on how large a portion of the project rebuilds, and depending on what kind of Mac you’re on (you really notice just how slow a MacBook Air is, by comparison, when building large projects ;)). Not having to wait that out every time I make a mistake has been a huge productivity boost for me.

What makes this even more helpful is that error messages form the build will come in and show in the editor one by one, as the build encounters them. So even if your build takes, say, 10 seconds, chances are you see your current line of code turn red after just a second or two if you made a mistake. Just fix it, press build again, and off you go.

This is just a small overview of how Fire integrates the build cycle into the IDE, and many of its subtleties are hard to do justice by just describing them. Give Fire a spin for yourself to see how this all works out in action — and make sure to let us know what you think!

Profile photo of marc

by marc

Staring into the Fire: Search and Replace

August 4, 2014 in Fire

This post is part of a series in which I want to take a closer look at some of the features and functionality in Fire, our new IDE for the Mac. In this post, I’d like to look at Search and Replace.

Search and Replace is a core feature of any development environment, so of course Fire has sophisticated support for it. The basics work pretty much exactly how you would expect, but Fire goes a bit beyond, so let’s look at the feature in detail.

To start with, as you would expect, you invoke Find/Replace using the standard Cmd-F keyboard shortcut (or via Edit|Find in the menu), which brings up the Find/Replace popup:

Here, you can type a search term and — as you’d expect — you can also choose whether this search term should be treated case sensitive, whether to match whole words/tokens only, or whether to treat the term as a RegEx. As you make your selection here, you will see that it will automatically reflect in the open editor, highlighting every occurrence of the search term in text marker yellow. This will persist even as you dismiss the Find/Replace popover.

What’s more, the search term and settings will automatically synchronize between all files you have open — all across your project, and even across multiple solutions. So as you switch files, or switch to a different document window, you will see your search term is highlighted everywhere. And, like just about all state in Fire, it will also persist across restart of the IDE.

The Find/Replace popover gives you the usual options to Find Next, Find Previous, and of course to replace either one or all occurrences of the search term with a new string.

After you dismiss the Find/Replace popover, these options continue be available via keyboard shortcuts and the Edit|Find menu. Cmd-G will jump to the next occurrence, and Shift-Cmd-G will jump to the previous, both allowing you to cycle round-and-round in the current file. Option-Cmd-G will replace the current/next occurrence of the search term, while Control-Option-Cmd-G will replace all in the entire file.

When replacing, you will notice that the editor also highlights each occurrence of the replace term as well, with a more subtle yellow. This highlighting allows you to easily keep track of what matches your search and what has been replaced already.

If you had enough of your search, you can clear the search term, and make the yellow highlights disappear with it, by pressing Control-Option-Cmd-F (or choosing Clear Search Term from the Edit|Find menu).

But that’s not all. One frequent task while navigating code is navigating between occurrences of the same token, so Fire has a shortcut for that as well. When the cursor is on a word/token, you can press Control-Option-Right or Control-Option-Left to quickly jump to the next (or previous) occurrence of that token. Fire will automatically make the token at the cursor the current search term (so you will see it highlighted all across the file). If not already turned on, Fire will also temporarily enable the “whole words only” option for this search to make sure you only find the exact token (if you want to jump from one use of ‘i‘ to the next, you don’t want to also hit the ‘i’ in ‘begin‘).

When you do a manual search later, the “whole words only” will automatically revert back to its original setting. You’ll find that the Control-Option-Right or Control-Option-Left navigation is something that, once you’re used to it, you can no longer live without

All in all, Fire’s Find and Replace support is well-rounded and — along with Fire’s other navigating mechanisms that I’ll dive into in another post — designed to make it really easy and intuitive to find your way around your code.