Category Archives: Programming

Why designed a front-end programming language from scratch

Today’s programming languages have traditionally been created by the tech giants. These languages are made up of millions of lines of code, so the tech giants only invest in incremental, non-breaking changes that address their business concerns. This is why innovation in popular languages like C, Java, and JavaScript is depressingly slow.

Open-source languages like Python and Ruby gained widespread industrial use by solving backend problems at startup scale. Without the constraints of legacy code and committee politics, language designers are free to explore meaningful language innovation. And with compile-to-VM languages, it has become cheap enough for individuals and startups to create the future of programming languages themselves.

Open-source language innovation has not yet disrupted front-end programming. We still use the same object-oriented model that took over the industry in the 1980s. The tech giants are heavily committed to this approach, but open-source has made it possible to pursue drastically different methods.

Two years ago, I began to rethink front-end programming from scratch. I quickly found myself refining a then-obscure academic idea called Functional Reactive Programming. This developed into Elm, a language that compiles to JavaScript and makes it much easier to create highly interactive programs.

Since the advent of Elm, a lively and friendly community has sprung up, made up of everyone from professional developers to academics to beginners who have never tried functional programming before. This diversity of voices and experiences has been a huge help in guiding Elm towards viability as a production-ready language.

The community has already created a bunch of high quality contributions that are shaping the future of Elm and are aiming to shape the future of front-end programming.

Dev tools

Early on, I made it a priority to let people write, compile, and use Elm programs directly from their browser. No install, no downloads. This interactive editor made it easy for beginners and experts alike to learn Elm and start using it immediately.

In-browser compilation triggered lots of discussion, ideas, and ultimately contributions. Mads Flensted-Urech added in-line documentation for all standard libraries. Put your cursor over a function, and you get the type, prose explanation, and link to the library it comes from. Laszlo Pandy took charge of debugging tools. He is focusing on visualizing the state of an Elm program as time passes, even going so far as pausing, rewinding, and replaying events.

Runtime

I designed Elm to work nicely with concurrency. Unfortunately, JavaScript’s concurrency support is quite poor with questionable prospects for improvement. I decided to save the apparent implementation quagmire for later, but John P. Mayer decided to make it happen. He now has a version of the runtime that can automatically multiplex tasks across many threads, all implemented in JavaScript.

Common to all of these cases are driven individuals who knew they could do it better. This is how Elm got started and how it caught the attention of Prezi, a company also not content to accept JavaScript as the one and only answer for front-end development. I have since joined the company for the express purpose of furthering work on Elm.

We do not need to sit and hope that the tech giants will someday do an okay job. We can create the future of front-end programming ourselves, and we can do it now.

 

Hacking with a Hacker

What is it like to hack with one of the original hackers? It is certainly much different than what Appears to be the modern rendition of hacking. My experience was not getting really drunk with tons of junk food. It was not working on “beautiful” designs or “authentic” typography. It was not so much about sharing with the world as it was sharing with your peers. It had a very different feel to it than the “hacker culture” Promoted by some of the top technical Silicon Valley companies. It felt more “at home”, less dreamy, and more memorable.

I meet with Bill Gosper every so Often; I had the pleasure of giving him a tour of Facebook when I worked there. (He was so surprised that they had Coke in the glass bottles there, just like the old days.)

He is still very much a hacker, a thinker, a tinkerer, and a wonderer. Every time I meet up with him, he has a new puzzle for me, or someone around him, to solve, whether it’s really clever compass constructions, circle packing, block building, Game of Life automata solving, or even something more tangible like a Buttonhole homemade trap (which was affixed to my shirt for no less than two weeks!). He is also the bearer of interesting items, such as a belt buckle he gave me roomates depicts, in aluminum, a particular circle loose packing.
Gosper succeeding in tricking me with the Buttonhole Trap
When we meet up, all we do is hack. Along with him and one of his talented young students, we all work on something. Anything interesting, really. Last time we met up, we resurrected an old Lisp machine and did some software archeology. I brought over some of the manuals I own, like the great Chinual, and he brought over a dusty old 1U rackmount Alpha machine with OpenGenera installed. After passing a combination of Hurdles, such as that the keyboard was not interfacing with the computer Correctly, we finally got it to boot up. Now, I got to see with my own eyes, a time capsule containing a lot of Bill’s work from the 70s, 80s, and 90s, roomates could only be commanded and Examined through Zmacs dired and Symbolics Common Lisp. Our next goal was to get Symbolics Macsyma fired up on the old machine.

There was trouble with starting it up. License issues were one problem, finding and loading all of the files were compiled another. Running applications on a Lisp machine is very different than what we do today on modern machines, Windows or UNIX. There’s no. Exe file to click, or. App bundle to start up, or even a single. / File to execute. Usually it’s a collection of compiled “fast loading” or “fasl” files that get loaded side-by-side with the operating system. The application, in essence, Becomes a part of the OS.

In hacker tradition, we were Able to bypass the license issues by modifying the binary directly in Lisp. Fortunately, such as Lisp makes things easy disassembly. But how do we load the damn thing? Bill frustratingly muttered, “It’s been at least 20 years since I’ve done it. I just do not remember. “I, being an owner of MacIvory Symbolics Lisp machines, fortunately did remember how to load programs. “Bill, how about LOAD SYSTEM Macsyma?” He typed it into the native Lisp “Listener 2” window (we kept “Listener 1” for debugging), sometimes making a few typing mistakes, but finally succeeding, and then we saw the stream of files loading. We all Shouted in joy that progress was being made. I recall Bill was especially astounded at how fast everything was loading. This was on a fast Alpha machine with gobs of memory. It must have been much slower on the old 3600s they used back in the day.
The Lisp Machine Manual, or Chinual
It was all done after a few minutes, and Macsyma was loaded. To me, this was a sort of holy grail. I personally have Macsyma for Windows (which he uses in a VirtualBox machine on his 17 “MacBook), and I’ve definitely used Maxima. But Macsyma is something I’ve never seen. It was something that seems to have disappeared with history, something I have not been Able to find a copy of in the last decade.

Bill said, “let’s see if it works.” And he typed 1 +1; in, and sure enough, the result was 2. He saw I was bubbling with excitement and asked me if I’d like to try anything. “I’d love to,” and he handed the keyboard over to me and I typed in my canonical computer algebra test: integrate (sqrt (tan (x)), x);, roomates computes the indefinite integral
—- √ ∫ tanθ dθ
Out came the four-term typeset result of logarithms and arctangents, plus a fifth term I’d never seen before. “I’ve never seen any computer algebra system add that fifth term,” I said, “but it does not look incorrect.” The fifth term was a floored expression, Whose Increased value with the period of the function preceding it. “Let’s plot it,” Bill said. He plotted it using Macsyma’s menu interface, and it was what appeared to be an increasing, non-periodic function. I think we determined it was properly handled Because Macsyma branch cuts, with other systems have been known to be unorthodox about. It definitely had a pragmatic feel to it.

Now, Bill wanted to show us some interesting things; however all of Bill’s recent work Macsyma was on his laptop. How do we connect this ancient to a modern Macintosh hardware? We needed to get the machine onto the network, and networking with old machines is not my forte.

Fortunately, Stephen Jones, a friend of Bill’s and seemingly an expert at a rare combination of technical tasks, showed up. He Was able to do things that Neither Bill nor I could do on such an old machine. In only a few moments, he Was able to get Bill’s Mac talking to the Alpha, roomates shared a portion of its file system with Genera. “Will there be enough space on the Alpha for Macsyma my files?” Bill asked Stephen. “Of course, there’s ton’s of space.” We finally got Bill’s recent work transferred onto the machine.
Bill hacking in Macsyma in OpenGenera (Image courtesy of Stephen M. Jones)
We spent the rest of the night hacking on math. He Demonstrated to us what it was like to do a real mathematician’s work at the machine. He debuted some of his recent work. He went though a long chain of reasoning, showing us the line-after-line in Macsyma, number theoretic amazing to do things I’ve never seen before.

I did ask Bill why he does not publish more often. His previous publications have been landmarks: his algorithm for hypergeometric series and his summation algorithm for playing the Game of Life at light speed. He RESPONDED, “when there’s something interesting to publish, it’ll be published.” He seemed to have a sort of disdain for “salami science”, where scientific and mathematical papers present the thinnest possible “slice” or result possible.

Bill is certainly a man that thinks in a different way than most of us do. He is still hacking at mathematics, and still as impressive as before. I’m very fortunate to have met him, and I was absolutely delighted to see that even at 70 years old, his mind is still as sharp as can be, and it’s still being used to do interesting, Gosper-like mathematics.

And you would not believe it. We all were ready to head home at around 9 PM.

Official feedback on OpenGL 4.4 thread

 SIGGRAPH – Anaheim, CA – The Khronos™ Group today announced the immediate release of the OpenGL® 4.4 specification,bringing the very latest graphics functionality to the most advanced and widely adopted cross-platform 2D and 3D graphics API (application programming interface). OpenGL 4.4 unlocks capabilities of today’s leading-edge graphics hardware while maintaining full backwards compatibility, enabling applications to incrementally use new features while portably accessing state-of-the-art graphics processing units (GPUs) across diverse operating systems and platforms. Also, OpenGL 4.4 defines new functionality to streamline the porting of applications and titles from other platforms and APIs. The full specification and reference materials are available for immediate download at http://www.opengl.org/registry.

In addition to the OpenGL 4.4 specification, the OpenGL ARB (Architecture Review Board) Working Group at Khronos has created the first set of formal OpenGL conformance tests since OpenGL 2.0. Khronos will offer certification of drivers from version 3.3, and full certification is mandatory for OpenGL 4.4 and onwards. This will help reduce differences between multiple vendors’ OpenGL drivers, resulting in enhanced portability for developers.

New functionality in the OpenGL 4.4 specification includes:

Buffer Placement Control (GL_ARB_buffer_storage)
Significantly enhances memory flexibility and efficiency through explicit control over the position of buffers in the graphics and system memory, together with cache behavior control – including the ability of the CPU to map a buffer for direct use by a GPU.

Efficient Asynchronous Queries
(GL_ARB_query_buffer_object)
Buffer objects can be the direct target of a query to avoid the CPU waiting for the result and stalling the graphics pipeline. This provides significantly boosted performance for applications that intend to subsequently use the results of queries on the GPU, such as dynamic quality reduction strategies based on performance metrics.

Shader Variable Layout (GL_ARB_enhanced_layouts)
Detailed control over placement of shader interface variables, including the ability to pack vectors efficiently with scalar types. Includes full control over variable layout inside uniform blocks and enables shaders to specify transform feedback variables and buffer layout.

Efficient Multiple Object Binding (GL_ARB_multi_bind)
New commands which enable an application to bind or unbind sets of objects with one API call instead of separate commands for each bind operation, amortizing the function call, name space lookup, and potential locking overhead. The core rendering loop of many graphics applications frequently bind different sets of textures, samplers, images, vertex buffers, and uniform buffers and so this can significantly reduce CPU overhead and improve performance.

Streamlined Porting of Direct3D applications

A number of core functions contribute to easier porting of applications and games written in Direct3D including GL_ARB_buffer_storage for buffer placement control, GL_ARB_vertex_type_10f_11f_11f_rev which creates a vertex data type that packs three components in a 32 bit value that provides a performance improvement for lower precision vertices and is a format used by Direct3D, and GL_ARB_texture_mirror_clamp_to_edge that provides a texture clamping mode also used by Direct3D.Extensions released alongside the OpenGL 4.4 specification include:

Bindless Texture Extension (GL_ARB_bindless_texture)
Shaders can now access an effectively unlimited number of texture and image resources directly by virtual addresses. This bindless texture approach avoids the application overhead due to explicitly binding a small window of accessible textures. Ray tracing and global illumination algorithms are faster and simpler with unfettered access to a virtual world’s entire texture set.

Sparse Texture Extension (GL_ARB_sparse_texture)
Enables handling of huge textures that are much larger than the GPUs physical memory by allowing an application to select which regions of the texture are resident for ‘mega-texture’ algorithms and very large data-set visualizations.

OpenGL BOF at SIGGRAPH, Anaheim, CA July 24th 2013
There is an OpenGL BOF “Birds of a Feather” Meeting on Wednesday July 24th at 7-8PM at the Hilton Anaheim, California Ballroom A & B, where attendees are invited to meet OpenGL implementers and developers and learn more about the new OpenGL 4.4 specification.

TSP Symposium 2013 Keynotes to Focus on Quality Practices for Critical Software

The Carnegie Mellon University Software Engineering Institute (SEI) has announced the slate of software engineering thought-leaders who will serve as keynote speakers for the Team Software Process (TSP) Symposium 2013. Held in Dallas, Texas, on September 16-19, the TSP Symposium 2013 keynote line-up includes Bill Curtis, senior vice president and chief scientist with Cast Software; Enrique Ibarra, senior vice president of technology of the Mexican Stock Exchange (BMV); and Robert Behler, chief operating officer of the SEI.

The symposium theme, When Software Really Matters, explores the idea that when product quality is critical, high-quality practices are the best way to achieve it.

“When a software system absolutely must work correctly, quality must be built in from the start. A disciplined approach to quality also offers the benefit of lower lifecycle costs. The TSP promotes the application of practices that lead to superior, high-quality products,” said James McHale, TSP Symposium 2013 technical chair. “Our keynote speakers and representatives from industry and government organizations from around the world will share how using TSP helps organizations build quality in from the start when there’s no room for error.”

  • Curtis will assert that the stakes for software-caused operational problems are now larger than ever, approaching a half-billion dollars per incident. Every other aspect of the business is managed by numbers, including IT operations. Software lags behind, however, because the culture of craftsmanship still prevails. Curtis’s talk will challenge that culture: Quality measurement will be challenged for under-measuring non-functional, structural quality, the cause of many operational disasters. Productivity measurement will be challenged for not penalizing baselines when rework is shifted into future releases as technical debt. Software measurement will be challenged to better express outcomes in terms that justify investments for improving quality. The word “quality” will be challenged as the wrong way to frame the argument. Curtis will propose a measurement stack or measurement pyramid to help translate software numbers to business numbers. At the foundation of this pyramid are the Personal Software Process (PSP) and TSP.
  • Ibarra will detail the Mexican Stock Exchange’s (BMV) broad plan of technological renovation that included migration to a new state-of-the-art data center and creating new operational systems with better functionalities and quality attributes. Since 2005, the BMV, which is responsible for operating the cash and derivatives market of the country and is the only exchange in Mexico, has faced the constant challenge of accommodating an exponential growth of demand for its transactional services as well as pressure from the market to offer services with better response times and functionalities. One of the most challenging software projects included in this technological renovation plan was the redesign and construction of the operational system known as the trading engine, which has strict and ambitious requirements for speed (latency), scalability, and continuous availability. The new system, which was to be designed and built internally, and the project were called MoNeT. The BMV had two goals for MoNeT: making sure a carefully considered and reviewed system architecture was in place prior to building the system and adopting a software development process that maximizes the quality of the new system and ensures that it complies with its intended quality attributes. Ibarra will describe the most relevant aspects of the MoNeT project, its performance in production, and the business impact it had on the BMV.
  • Behler, one of only 139 individuals qualified as pilots of the Lockheed SR-71 Blackbird aircraft, will describe his experience flying the fastest, most physically demanding aircraft in the world to gather vital data during the Cold War and the teamwork approach it took to develop the aircraft. The SR-71 was developed in the 1960s with myriad sophisticated sensors used to acquire highly specific intelligence data. The aircraft remains an icon of American aerospace engineering to this day and is considered to be the most effective reconnaissance aircraft in history.

In addition to the keynote speakers, substantial technical program, and organized networking events, the TSP Symposium 2013 also offers practitioners an in-depth learning opportunity with full-day tutorials on introductory and advanced TSP concepts.

“I am very excited about this year’s lineup of keynote speakers and technical presenters. The symposium should be stimulating with presentations on a broad array of topics related to quality-focused software development. It is also an excellent way for participants to network and exchange diverse ideas about how they have used the PSP/TSP approach to achieve their software quality goals,” said Mark Kasunic, Symposium co-chair.

5 Coding Hacks to Reduce GC Overhead

In this post we’ll look at five ways in roomates efficient coding we can use to help our garbage collector CPU spend less time allocating and freeing memory, and reduce GC overhead. Often Long GCs can lead to our code being stopped while memory is reclaimed (AKA “stop the world”). Duke_GCPost

Some background

The GC is built to handle large amounts of allocations of short-lived objects (think of something like rendering a web page, where most of the objects allocated Become obsolete once the page is served).

The GC does this using what’s called a “young generation” – a heap segment where new objects are allocated. Each object has an “age” (placed in the object’s header bits) defines how many roomates collections it has “survived” without being reclaimed. Once a certain age is reached, the object is copied into another section in the heap called a “survivor” or “old” generation.

The process, while efficient, still comes at a cost. Being Able to reduce the number of temporary allocations can really help us increase of throughput, especially in high-scale applications.

Below are five ways everyday we can write code that is more memory efficient, without having to spend a lot of time on it, or reducing code readability.

1. Avoid implicit Strings

Strings are an integral part of almost every structure of data we manage. Being much heavier than other primitive values, they have a much stronger impact on memory usage.

One of the most important things to note is that Strings are immutable. They can not be modified after allocation. Operators such as “+” for concatenation actually allocate a new String containing the contents of the strings being joined. What’s worse, is there’s an implicit StringBuilder object that is allocated to actually do the work of combining them.

For example –

1
a = a + b; / / a and b are Strings
The compiler generates code comparable behind the scenes:

1
StringBuilder temp = new StringBuilder (a).
2
temp.append (b);
3
a = temp.toString () / / a new string is allocated here.
4
/ / The previous “a” is now garbage.
But it gets worse.

Let’s look at this example –

1
String result = foo () + arg;
2
result + = boo ();
3
System.out.println (“result =” + result);
In this example we have 3 StringBuilders allocated in the background – one for each plus operation, and two additional Strings – one to hold the result of the second assignment and another to hold the string passed into the print method. That’s 5 additional objects in what would otherwise Appear to be a pretty trivial statement.

Think about what happens in real-world scenarios such as generating code a web page, working with XML or reading text from a file. Within a nested loop structures, you could be looking at Hundreds or Thousands of objects that are implicitly allocated. While the VM has Mechanisms to deal with this, it comes at a cost – one paid by your users.

The solution: One way of reducing this is being proactive with StringBuilder allocations. The example below Achieves the same result as the code above while allocating only one StringBuilder and one string to hold the final result, instead of the original five objects.

1
StringBuilder value = new StringBuilder (“result =”);
2
value.append (foo ()). append (arg). append (boo ());
3
System.out.println (value);
By being mindful of the way Strings are implicitly allocated and StringBuilders you can materially reduce the amount of short-term allocations in high-scale code locations.

2. List Plan capacities

Dynamic collections such as ArrayLists are among the most basic dynamic structures to hold the data length. ArrayLists and other collections such as HashMaps and implemented a Treemaps are using the underlying Object [] arrays. Like Strings (Themselves wrappers over char [] arrays), arrays are also immutable. Becomes The obvious question then – how can we add / put items in their collections if the underlying array’s size is immutable? The answer is obvious as well – by allocating more arrays.

Let’s look at this example –

1
List <Item> <Item> items = new ArrayList ();
2

3
for (int i = 0; i <len; i + +)
4
{
5
Item item = readNextItem ();
6
items.add (item);
7
}
The value of len Determines the ultimate length of items once the loop finishes. This value, however, is unknown to the constructor of the ArrayList roomates allocates a new Object array with a default size. Whenever the internal capacity of the array is exceeded, it’s replaced with a new array of sufficient length, making the previous array of garbage.

If you’re executing the loop Welcome to Thunderbird times you may be forcing a new array to be allocated and a previous one to be collected multiple times. For code running in a high-scale environment, these allocations and deallocations are all deducted from your machine’s CPU cycles.
%0

Variabel di Shell Script

In the previous issue we’ve become acquainted with a shell script and managed to create a very simple shell script. If we look, we did not perform any processing on the shell script. We only show a message on the screen and execute commands on the shell through shell script. What if we want to make the program more interactive shell script?

As with any programming language, shell script also serves to recognize the variables that can hold information temporarily for a variety of purposes, for example to compute or determine the output results. You may make as much as possible or use a variable in your shell script. Name the variables are independent, large and small letters should, but make it easier to remember, make it a habit to create standard rules in the manufacture of the variable name. At this writing, all variables will be written in lowercase.

Variables can be divided into two types, namely environment variables and user variables. Environment variables are variables that have been previously determined as a part of the shell used (bash). By default, the name of this variable using all capital letters. Example of this is the $ USER variable that will contain the user name you are currently using, $ HOME home directory which contains the address of the user that is used, and so forth. To display the entire value of an existing environment variable, you can use the set command in the terminal (Figure 1). User variable is the variable name specified by the user themselves and not by the shell used.

Variables can be accessed by using the dollar sign ($) before the variable name, for example, we have a variable named “my name”, to access the value stored in the variable, we use the $ my name. To give value to a variable, we use the sign “=” is immediately followed by the value we give without any spaces, for example my name = Willy. What if the value that we want to give is a sentence? Use double quotes as the opening and closing value of a variable, such as my name = “Willy Sudiarto Raharjo”. For example, see listing 1 and try running on your computer. Seen that the value of the variable Sudiarto be regarded as a command and not part of the variable because it is not enclosed in double quotation marks. Please be careful in giving a value to a variable.

You can combine environment variables and user variables in a shell script is the same, as in listing 2. What if want to write a message using the $ character, such as “It cost me $ 15”? If we are not careful, it could be a shell script would be wrong to interpret the information that we provide and try to take the value of variable 1 (which will not contain any) and display it as a “price 5”. To fix this, use the escape character to indicate that the next character will be recognized as a regular character and not as a substitute for a variable, which marks the backslash “\” as in listing 3.

One character that needs more attention is the backtick character “` “(position number 1 on the left side your keyboard) because this character has a special function in shell programming, which is able to accommodate the output of a shell command in a variable. As an example, we will hold the result of the date command into a variable date and display its contents using the echo command as in listing 4.

To be able to receive input from the user and store it into a variable, we can use the read function is followed by the name of the variable that we want to use to store the values ​​as in Example 5 listings.

Integrating C++ with QML

Introduction

Qt Quick’s QML language makes it easy to do many things, especially fancy animated user interfaces. However, some things either can’t be done or are not suitable for implementing in QML, such as:

  1. Getting access to functionality outside of the QML/JavaScript environment.
  2. Implementing performance critical functions where native code is desired for efficiency.
  3. Large and/or complex non-declarative code that would be tedious to implement in JavaScript.

As we’ll see, Qt makes it quite easy to expose C++ code to QML. In this blog post I will show an example of doing this with a small but functional application.

The example is written for Qt 5 and uses the Qt Quick Components so you will need at least Qt version 5.1.0 to run it.

Overview

To expose a C++ type having properties, methods, signals, and/or slots to the QML environment, the basic steps are:

  1. Define a new class derived from QObject.
  2. Put the Q_OBJECT macro in the class declaration to support signals and slots and other services of the Qt meta-object system.
  3. Declare any properties using the Q_PROPERTY macro.
  4. Call qmlRegisterType() in your C++ main program to register the type with the Qt Quick engine.

For all the details I refer you to the Qt documentation section Exposing Attributes of C++ Types to QML and the Writing QML Extensions with C++ tutorial.

Ssh Key Generator

For our code example, we want a small application that will generate ssh public/private key pairs using a GUI. It will present the user with controls for the appropriate options and then run the program ssh-keygen to generate the key pair.

I implemented the user interface using the new Qt Quick Controls since it was intended as a desktop application with a desktop look and feel. I initially developed the UX entirely by running the qmlscene program directly on the QML source.

The UI prompts the user for the key type, the file name of the private key to generate and an optional pass phrase, which needs to be confirmed.

The C++ Class

Now that have the UI, we will want to implement the back end functionality. You can’t invoke an external program directly from QML so we have to write it in C++ (which is the whole point of this example application).

First, we define a class that encapsulates the key generation functionality. It will be exposed as a new class KeyGenerator in QML. This is done in the header file KeyGenerator.h below.

#ifndef KEYGENERATOR_H
#define KEYGENERATOR_H

#include <QObject>
#include <QString>
#include <QStringList>

// Simple QML object to generate SSH key pairs by calling ssh-keygen.

class KeyGenerator : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
    Q_PROPERTY(QStringList types READ types NOTIFY typesChanged)
    Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)
    Q_PROPERTY(QString passphrase READ filename WRITE setPassphrase NOTIFY passphraseChanged)

public:
    KeyGenerator();
    ~KeyGenerator();

    QString type();
    void setType(const QString &t);

    QStringList types();

    QString filename();
    void setFilename(const QString &f);

    QString passphrase();
    void setPassphrase(const QString &p);

public slots:
    void generateKey();

signals:
    void typeChanged();
    void typesChanged();
    void filenameChanged();
    void passphraseChanged();
    void keyGenerated(bool success);

private:
    QString _type;
    QString _filename;
    QString _passphrase;
    QStringList _types;
};
#endif

Next, we need to derive our class from QObject. We declare any properties that we want and the associated methods. Notify methods become signals. In our case, we want to have properties for the selected key type, the list of all valid ssh key types, file name and pass phrase. I arbitrarily made the key type a string. It could have been an enumerated type but it would have made the example more complicated.

Incidentally, a new feature of the Q_PROPERTY macro in Qt 5.1.0 is the MEMBER argument. It allows specifying a class member variable that will be bound to a property without the need to implement the setter or getter functions. That feature was not used here.

We declare methods for the setters and getters and for signals. We also declare one slot called generateKey(). These will all be available to QML. If we wanted to export a regular method to QML, we could mark it with Q_INVOCABLE. In this case I decided to make generateKey() a slot since it might be useful in the future but it could have just as easily been an invocable method.

Finally, we declare any private member variables we will need.

C++ Implementation

Now let’s look at the implementation in KeyGenerator.cpp. Here is the source code:

#include <QFile>
#include <QProcess>
#include "KeyGenerator.h"

KeyGenerator::KeyGenerator()
    : _type("rsa"), _types{"dsa", "ecdsa", "rsa", "rsa1"}
{
}

KeyGenerator::~KeyGenerator()
{
}

QString KeyGenerator::type()
{
    return _type;
}

void KeyGenerator::setType(const QString &t)
{
    // Check for valid type.
    if (!_types.contains(t))
        return;

    if (t != _type) {
        _type = t;
        emit typeChanged();
    }
}

QStringList KeyGenerator::types()
{
    return _types;
}

QString KeyGenerator::filename()
{
    return _filename;
}

void KeyGenerator::setFilename(const QString &f)
{
    if (f != _filename) {
        _filename = f;
        emit filenameChanged();
    }
}

QString KeyGenerator::passphrase()
{
    return _passphrase;
}

void KeyGenerator::setPassphrase(const QString &p)
{
    if (p != _passphrase) {
        _passphrase = p;
        emit passphraseChanged();
    }
}

void KeyGenerator::generateKey()
{
    // Sanity check on arguments
    if (_type.isEmpty() or _filename.isEmpty() or
        (_passphrase.length() > 0 and _passphrase.length() < 5)) {
        emit keyGenerated(false);
        return;
    }

    // Remove key file if it already exists
    if (QFile::exists(_filename)) {
        QFile::remove(_filename);
    }

    // Execute ssh-keygen -t type -N passphrase -f keyfileq
    QProcess *proc = new QProcess;
    QString prog = "ssh-keygen";
    QStringList args{"-t", _type, "-N", _passphrase, "-f", _filename};
    proc->start(prog, args);
    proc->waitForFinished();
    emit keyGenerated(proc->exitCode() == 0);
    delete proc;
}

The constructor initializes some of the member variables. For fun, I used the new initializer list feature of C++11 to initialize the _types member variable which is of type QStringList. The destructor does nothing, at least for now, but is there for completeness and future expansion.

Getter functions like type() simply return the appropriate private member variable. Setters set the appropriate variables, taking care to check that the new value is different from the old one and if so, emitting the appropriate signal. As always, please note that signals are created by the Meta Object Compiler and do not need to be implemented, only emitted at the appropriate times.

The only non-trivial method is the slot generateKey(). It does some checking of arguments and then creates a QProcess to run the external ssh-keygen program. For simplicity and because it typically executes quickly, I do this synchronously and block on it to complete. When done, we emit a signal that has a boolean argument that indicates the key was generated and whether it succeeded or not.

QML Code

Now let’s look at the QML code in main.qml:

// SSH key generator UI

import QtQuick 2.1
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.0
import QtQuick.Dialogs 1.0
import com.ics.demo 1.0

ApplicationWindow {
    title: qsTr("SSH Key Generator")

    statusBar: StatusBar {
    RowLayout {
        Label {
            id: status
            }
        }
    }

    width: 369
    height: 166

    ColumnLayout {
        x: 10
        y: 10

        // Key type
        RowLayout {
            Label {
                text: qsTr("Key type:")
            }
            ComboBox {
                id: combobox
                Layout.fillWidth: true
                model: keygen.types
                currentIndex: 2
            }
        }

        // Filename
        RowLayout {
            Label {
                text: qsTr("Filename:")
            }
            TextField {
                id: filename
                implicitWidth: 200
                onTextChanged: updateStatusBar()
            }
            Button {
                text: qsTr("&Browse...")
                onClicked: filedialog.visible = true
            }
        }

        // Passphrase
        RowLayout {
            Label {
                text: qsTr("Pass phrase:")
            }
            TextField {
                id: passphrase
                Layout.fillWidth: true
                echoMode: TextInput.Password
                onTextChanged: updateStatusBar()
            }

        }

        // Confirm Passphrase
        RowLayout {
            Label {
                text: qsTr("Confirm pass phrase:")
            }
            TextField {
                id: confirm
                Layout.fillWidth: true
                echoMode: TextInput.Password
                onTextChanged: updateStatusBar()
            }
        }

        // Buttons: Generate, Quit
        RowLayout {
            Button {
                id: generate
                text: qsTr("&Generate")
                onClicked: keygen.generateKey()
            }
            Button {
                text: qsTr("&Quit")
                onClicked: Qt.quit()
            }
        }

    }

    FileDialog {
        id: filedialog
        title: qsTr("Select a file")
        selectMultiple: false
        selectFolder: false
        nameFilters: 
        selectedNameFilter: "All files (*)"
        onAccepted: {
            filename.text = fileUrl.toString().replace("file://", "")
        }
    }

    KeyGenerator {
        id: keygen
        filename: filename.text
        passphrase: passphrase.text
        type: combobox.currentText
        onKeyGenerated: {
            if (success) {
                status.text = qsTr('<font color="green">Key generation succeeded.</font>')
            } else {
                status.text = qsTr('<font color="red">Key generation failed</font>')
            }
        }
    }

    function updateStatusBar() {
        if (passphrase.text != confirm.text) {
            status.text = qsTr('<font color="red">Pass phrase does not match.</font>')
            generate.enabled = false
        } else if (passphrase.text.length > 0 && passphrase.text.length < 5) {
            status.text = qsTr('<font color="red">Pass phrase too short.</font>')
            generate.enabled = false
        } else if (filename.text == "") {
            status.text = qsTr('<font color="red">Enter a filename.</font>')
            generate.enabled = false
        } else {
            status.text = ""
            generate.enabled = true
        }
    }

    Component.onCompleted: updateStatusBar()
}

The preceding code is a little long, however, much of the work is laying out the GUI components. The code should be straightforward to follow.

Note that we import com.ics.demo version 1.0. We’ll see where this module name comes from shortly. This makes a new QML type KeyGeneratoravailable and so we declare one. We have access to it’s C++ properties as QML properties, can call it’s methods and act on signals like we do withonKeyGenerated.

A more complete program should probably do a little more error checking and report meaningful error messages if key generation fails (we could easily add a new method or property for this). The UI layout could also be improved to make it properly resizable.

Our main program is essentially a wrapper like qmlscene. All we need to do to register our type with the QML engine is to call:

    qmlRegisterType<KeyGenerator>("com.ics.demo", 1, 0, "KeyGenerator");

This makes the C++ type KeyGenerator available as the QML type KeyGenerator in the module com.ics.demo version 1.0 when it is imported.

Typically, to run QML code from an executable, in the main program you would create a QGuiApplication and a QQuickView. Currently, to use the Qt Quick Components there is some additional work needed if the top level element is an ApplicationWindow or Window. You can look at the source code to see how I implemented this. I basically stripped down the code from qmlscene to the minimum of what was needed for this example.

Here is the full listing for the main program, main.cpp:

#include <QApplication>
#include <QObject>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQuickWindow>
#include <QSurfaceFormat>
#include "KeyGenerator.h"

// Main wrapper program.
// Special handling is needed when using Qt Quick Controls for the top window.
// The code here is based on what qmlscene does.

int main(int argc, char ** argv)
{
    QApplication app(argc, argv);

    // Register our component type with QML.
    qmlRegisterType<KeyGenerator>("com.ics.demo", 1, 0, "KeyGenerator");

    int rc = 0;

    QQmlEngine engine;
    QQmlComponent *component = new QQmlComponent(&engine);

    QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));

    component->loadUrl(QUrl("main.qml"));

    if (!component->isReady() ) {
        qWarning("%s", qPrintable(component->errorString()));
        return -1;
    }

    QObject *topLevel = component->create();
    QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);

    QSurfaceFormat surfaceFormat = window->requestedFormat();
    window->setFormat(surfaceFormat);
    window->show();

    rc = app.exec();

    delete component;
    return rc;
}

In case it is not obvious, when using a module written in C++ with QML you cannot use the qmlscene program to execute your QML code because the C++ code for the module will not be linked in. If you try to do this you will get an error message that the module is not installed.