C++ has become a scripting language
voices.canonical.com
voices.canonical.com
I'm not sure you get to claim a language is a scripting language and then ignore the boilerplate.
The equivalent python is 4 lines, just one more than the number of steps you're performing.
import sys
data = open(sys.argv[1]).readlines()
lines = sorted(data)
open(sys.argv[2], 'w').writelines(lines)
C++ is good at many things, but quickly creating readable scripts and live-coding with a REPL are not among them. #!/bin/sh
sort < $1 > $2
My preferred scripting language ;)Utility of shell goes down. Not because problems are represented as 'Text', but rather shell languages lack features like exception handling, proper error checking and many other things- Which make it difficult to write large programs in it.
As a next extension, you can learn Perl.
I assure you, after that you will not need anything ever.
I love it when people say things like this. As is their domain is the only domain in all programming.
For surely, you could write a competitive web browser in Perl. Or a first person shooter. Or a telecom system. Or a mars orbiter.
It makes you wonder why anyone ever invented anything else!
Languages I know are: C, Objective-C, Perl, PHP, Javascript, and bash. Languages I played in: Python, Ruby, C++, C#, lua, go.
I want to learn C++ as it has very good cross platform stuff. But don't know when to start. I want to learn python so I can help with mailpile, but don't know when to start. I want to learn go as I want to write my own chat protocol, but don't know when to start.
I am not biased with languages, I just don't know other languages and can't give a pros/cons comparing between them.
Not with PowerShell! PowerShell is amazing in how it takes the text pipe model of working and extends it to general purpose objects.
(Having access to all those .NET libraries is a nice bonus!)
sh script.sh
python script.py
So one line vs two lines import sys
open(sys.argv[1],'w').writelines(sorted(open(sys.argv[2]).readlines()))
Yep, bash is more readable for small scripts $ time sort < t > t-sh
real 0m0.016s
user 0m0.008s
sys 0m0.008s
$ time py -c "import sys; open(sys.argv[1],'w').writelines(sorted(open(sys.argv[2]).readlines()))" t-py t
real 0m0.088s
user 0m0.056s
sys 0m0.012s
BTW also a different result (I curled this page for the data).See my results here: http://pastebin.com/HMUErzee
1: http://stackoverflow.com/questions/9006596/is-the-unix-time-...
Code from https://github.com/rofrol/go-examples
I don't agree with that, in my opinion bash is more coincise while python is far more explicit and thus more understandable.
Python is not meant to be written in one line; the script could be rewritten in a readable way like this:
import sys
inp = open(sys.argv[1], 'r')
out = open(sys.argv[2], 'w')
out.writelines(sorted(inp))Including whitespace it's still half as long as the "11 line" core of the C++ script.
There's an unnecessary 'r'. Combined with the line rhythm established by opening the files in consecutive lines you ensure readers who would have been confused by the 'w' will quickly understand.
And the last line reads like programmer English; by which I mean English with a SVO word order. Not intuitive to the average person but quite parsable by anybody who's used a modern imperative language.
I can't even nitpick your choice of inp instead of input, the rhythm you setup and the contrast with 'out' means it's quite obvious what you mean.
Have an upvote.
import sys
reduce(lambda i, o: o.writelines(sorted(i)),
map(lambda args: open(*args),
zip(sys.argv[1:], ('r', 'w'))))
If Guido didn't despised FP so much maybe we could get a nicer lambda syntax... but here's anyway.I mean, this one line should be equally functional and .. it's shorter and even more understandable:
open(sys.argv[2], 'w').writelines(sorted(open(sys.argv[1]))
(Btw you're talking about a nicer lambda syntax but imho your example looks ugly because of all the unneeded stuff you've put into it) Main(string[] args) { File.WriteAllLines(args[1], File.ReadAllLines(args[0]).OrderBy(x => x).ToArray()); }
Excludes using statements, .net library references. project file, solution file, framework config file...I have invented a language called Croml, in which all source code compiles to the same program. This program reads in a file, sorts the lines, and writes it back out to another file. An empty source file accomplishes this task.
File.WriteAllLines(args[1], File.ReadAllLines(args[0]).OrderBy(x => x));
However, there's no Main in LINQPad which takes string[] args. Also File.WriteAllLines takes an array as its second parameter, while OrderBy returns an IEnumerable.
This bash script rewritten in python should be something like this:
import subprocess, sys
inp = open(sys.argv[1], 'r')
out = open(sys.argv[2], 'w')
sys.exit(subprocess.call('sort', stdin=inp, stdout=out, stderr=sys.stderr))
(I don't know why but it seems that the performance of this version are worse than the original proposed example with writelines/readlines)The real problem with bash is the mess you get when you start needing whitespace or arrays or error handling or non tabular objects or a computation not already implemented as a system program.
sort < "$1" > "$2"import sys; open(sys.argv[2], 'w').writelines(sorted(open(sys.argv[2], 'w').writelines())
(use-package :com.informatimago.common-lisp.cesarum.file) (setf (string-list-text-file-contents outpath) (sort (string-list-text-file-contents inpath) (function string<)))
Indeed, what kills languages like C or C++11 in the scripting domain, is the need for declarations and other kind of boiler plate. That said, with C++11 there are means to write a library requiring less declarations, but it's still a cultural problem (beside the hard work that it would require).
import sys
src = open(sys.argv[1])
dest = open(sys.argv[2], 'w')
dest.writelines(sorted(src)) lines = sorted(open(sys.argv[1]))
since Python files act as iterators over lines.Plus, he could have reduced lines even further to get down to about 6, like
vector<string> data;
string line;
for (ifstream ifile(argv[1]); getline(ifile, line);)
data.push_back(line);
sort(begin(data), end(data));
copy(begin(data), end(data), ostream_iterator<string>(ofstream(argv[2]), "\n"));
And his `return 0` was superfluous so I removed it.Unfortunately we work with iterator pairs in C++; if we had ranges like D does, we could turn those last two into
copy(sort(data), ...)
but alas we cannot."powerful string manipulation functions"
boost::algorithm::split (and the rest of algorithm, frankly) is unintuitive to use. Regex requires looking up the syntax every time. No encoding/unicode support. Literally 100's of popular string libraries, all incompatible, and that's not even counting all the homebrew. char* everywhere so lots of copying to work with string objects (which is what all of the algorithms work on). Dozens of different and slightly different ways of converting other types and object to/from strings. Poor string formatting functionality, and the solutions that exist are verbose and cumbersome (strstream, boost::format, ...) .
I still love the combination of low-level power and high-level abstraction that C++ provides, but string handling is one of the most problematic areas, in my experience (which is of course colored by the type of work I do, but still).
This entire "scripting language" vs. ? ("general purpose language"? "systems programming language"?) is really not well defined in the first place.
What makes some language a scripting language? Is Python a scripting language or a general purpose language? Scripting for a specific platform? "General" scripting language?
I think most people think of "scripting languages" as languages used for automating small tasks that aren't suitable (the languages, that is) for large applications. By that definition any general purpose language is automatically a "scripting" language but not the other way around.
And what does having a REPL vs. not or an interpreter vs. a compiler have to do with any of this?
The problem is that many discuss what they think a certain programming language is, without the proper bases to do so.
A well known paper that discusses those capabilities is the John Ousterhout's paper for the 1998 IEEE COMPUTER, "Scripting: Higher Level Programming for the 21st Century".
http://www.stanford.edu/~ouster/cgi-bin/papers/scripting.pdf
Do you want some kind of ISO/ANSI standard definition?
A lot. As a class, languages that can be executed by sending program text to stdin without polluting the execution environment are suitable for a whole class of programming techniques that languages that can't aren't.
For example, heredoc-ing to inline one language's code into another, generating code at runtime, or executing on another machine over ssh are much trickier propositions in Java or C++ than they are in Awk or Python.
REPL availability matters because it's common to use one or more REPLs as a primary UI to a machine. Lots of people use Bash or another *sh, some people use Python or a Lisp, but I've yet to hear of anyone using a C++ REPL as their shell even if such a thing may exist.
Theoretically, these are properties of the implementation and not the language, but language features tend to be so coupled to that implementation decision that it doesn't matter. (go with its 'go run' is a maybe-exception)
We also can't have any meaningful discussion using your definition. What does "polluting the execution environment" mean? Are we restricting the discussion to platforms/languages where "stdin" has a meaning?
By it's nature, a scripting language's job is to "pollute it's environment", i.e. to perform some modification of the state of the system it is scripting. A scripting language is most certainly not a "filter", something that takes some input via a pipe and produces some output.
Mutating the environment isn't necessary to be a useful program. The techniques of "move the code to the data, not the data to the code" and "share by communicating, don't communicate by sharing" depend on this.
The actual implementation behaviors of C and Java prevent me from treating a remote system as an abstract, environment-free machine, at least without doing a ton of tooling. The almost unavoidable, unwanted side-effects on the local filesystem due to executing source code is what I'm referring to as pollution.
So if Python makes a .pyc file that's not pollution but gcc making an a.out is? How about we create a RAM disk, compile into that, and dispose of it after we're done?
A compiler is a process that takes source code as input. You simply need to draw your circle a little larger.
The reality is that the lines are blurry, definitely more blurry today then they were in 1998 (that paper that was referred to). They are blurrier because computers are faster and with more storage, compile is now more of a continuum with JIT and there are many languages that straddle multiple categories.
I've used C for "scripting", e.g. a "quick and dirty" parse some files and spit out some results and I use Python for "production" style very large applications. C++ has become more expressive and safer but I'm not sure what we get by saying it's a "scripting language".
A spectacular use of this ability is in using tcc as a linux bootloader. Instead of loading vmlinuz, it loads the C source for the kernel, compiles it, and boots the result. It doesn't even need an operating system (try that with python).
Actually, it seems such a thing does exist, and there are quite some people using it (like, CERN) -- see a recent link from proggit for a C REPL called "CINT" (and its top comments for a C++ REPL dubbed "Cling") at:
http://www.reddit.com/r/programming/comments/1lqdor/cint_is_...
A scripting language is a language L with respect to an environment E where a sequence of operation that can be performed manually in E (a script) can also be performed by invoking a program in language L.
A stronger definition can involve multiple environments E for the same language.
A general purpose language L with respect to an environment E is a language in which every possible application that can run in E can be performed by invoking a program written in language L.
Then again we can strengthen this definition by including multiple platforms or environments.
Most people I know use "scripting language" in a derogatory way, "it's only a scripting language, you can't use it for real applications" and often with respect to perfectly good general purpose languages (which is why this approach isn't always constructive).
Obviously the name "scripting" comes about from the fact that such langauges are intended for "scripting" automating interaction with "objects" (application scripting, HTML scripting, shell scripting, etc.), and that high-level features and on-the-fly execution are more important than performance.
I've never met anyone who thought Python wasn't a scripting language -- I mean, you run the Python interpreter on the script file. And I've never met anyone who would call a compiled language (C, Java, etc.) a scripting language. The distinction is pretty clear to me; maybe other people can think of counterexamples?
http://stackoverflow.com/questions/2998215/if-python-is-inte...
Do we need to compile to machine languages? What about a VM? What about the Python VM is different than the Java VM or the .NET VM? Is C# therefore a scripting language or a ______ language. (fill in the blank)
ActionScript? What about JIT compilers? JavaScript?
At any rate, I think you're trying to say scripting langugage == interpreted language but there are probably interpreted languages (let's say Prolog) that you wouldn't call scripting languages and there are compiled languages that can be used for "scripting". I agree that typically scripting languages are interpreted. But I would call Python a general purpose language and not a scripting language.
And then, everything always eventually compiles to machine code, some just do it at runtime!
Have you seen Oberon?
In the 80s, the same language, BASIC, could be either interpreted at runtime or compiled to intermediary code. And there was even a C language interpreter.
A surprisingly difficult question that I've wrestled with a lot (I did a PhD in "compilers and scripting languages" and people can be quite picky about semantics!). Here's how I think about it:
Wikipedia is more clear on this: http://en.wikipedia.org/wiki/Scripting_language "it is uncommon to use Java as a scripting language due to the lengthy syntax and restrictive rules about which classes exist in which files" -- I'd say this applies to C++11 as well.
* No static types
* No need to compile
* Having a REPL
Wouldn't their type systems be a big reason why? ML and Haskell have type systems very different from Java specifically because they went for systems that were inferable. F# has an iffy "just assume it is int" step to make it work with the C# type system. F#'s inference algorithm doesn't work as well, and it impacts how the language gets used. For example people tend to overuse the pipe operator because it helps the inference engine get the right type without annotations.
F# inference is left-to-right, which is one reason to use the |> operator, yes. F# had additional type inference, for instance, accessing members on a binding would infer object types, but they removed that. Haskell has a more complete type inference system.
I'm not seeing anything in C# that prohibits inference of types for fields, methods return types, or parameters. The type system C# has is essentially a subset of F#.
I concede that REPLs is not a must for a scripting language, but it will definitely make it more enjoyable ;)
Small nitpcik to the author: please define variables when you're going to use them, not C-style all at the beginning of the function. It makes code easier to understand. It doesn't make the reader wonder 'hey what's this variable going to be used for' then having to crawl through all code underneath it. It creates code that's easier to refactor. Also, but more arguably for such a small sample: http://stackoverflow.com/questions/1452721/why-is-using-name...
array = IO.readlines ARGV[0]
array.sort!
File.write ARGV[1], array.join("\n")
edit: get input and output file names from command lineBTW, I would never use Ruby for anything that needs performance, but for ease of use and readability it's really great.
lines = IO.readlines ARGV[0]
File.write ARGV[1], lines.sort.join('\n')
certainly more readable than the C++ even if you're unfamiliar with ruby. File.write ARGV[1], IO.readlines(ARGV[0]).sort.join('\n')
;) IO.write(ARGV[1], ARGF.lines.sort.join)Also, trim out the space between the arguments and kill the parenthesis for the optimal golfing.
Maybe this would fix it:
IO.write(ARGV.pop, ARGF.lines.sort.join('\n')) IO.write$*.pop,ARGF.lines.sort.join
And yes, it does work even without the space between `write` and `$*`.Also after testing, I realized the ('\n') is not required for join. When you call 'lines', it still has the '\n' character in the string, and when you join, it defaults to join without a delimiter, so it's putting them back together with the newline still there.
> File.write ARGV[1], (IO.readlines ARGV[0]).sort.join('\n')
not valid Ruby?
File.open(ARGV[1], 'w') { |file| file.write(File.read(ARGV[0]).lines.sort.join) }
http://stackoverflow.com/questions/8278680/ruby-undefined-me... ruby -e 'puts ARGF.sort' file.txt
Also, this reads stdin if the argument is omitted. import sys
data = open(sys.argv[1]).readlines()
data.sort()
open(sys.argv[2],'w').write(''.join(data)) sorted_lines = sorted(open(sys.argv[1]))
open(sys.argv[2]).writelines(sorted_lines) <?
$lines=file($argv[1]);
sort($lines);
file_put_contents($argv[2],implode("\n",$lines)); use strict;
use warnings;
open my $read,"<",$ARGV[0] or die $!;
my @lines = <$read>;
close $read;
open my $write,">",$ARGV[1] or die $!;
print $write $line foreach my $line(sort @lines);
close $write; use v5.12; # enables strictures
open my $in, "<", $ARGV[0];
open my $out, ">", $ARGV[1];
print $out sort <$in>;
Perl6: sub MAIN( $in, $out ) {
spurt( $out, open($in, chomp => False).lines.sort.join )
}
[EDIT: fixed typo in first example] my @files = map { IO::File->new($_->[0], $_->[1]) || die $! }
([shift, 'r'], [shift, 'w']);
$files[1]->print( sort $files[0]->getlines );
$_->close for @files;
And... use autodie;
open my $out, '>', $ARGV[1];
print {$out} sort do {open my $in, '<', $ARGV[0]; <$in>};It's actually really hard to completely rewrite that program in most scripting languages: they tend not to have the same concept of undefined behaviour.
'sys.argv[2]' in python (with sys.argv = ['thing.py']) is fully defined (raises an IndexError). 'argv[2]' in C++ (with argv = (char*[2]) { "./thing", 0 }) is undefined.
If you scripting language has an FFI library (ctypes in python, say) then you could probably do something equivalent.
import System.Environment
import Data.List
main = do
infile:outfile:_ <- getArgs
input <- readFile infile
writeFile outfile . unlines . sort . lines $ input [infile, outfile] <- getArgs
Also, the last two lines may be squeezed into one (though less readable): writeFile outfile =<< (unlines . sort . lines) `fmap` readFile infileOn your second point, I actually thought about writing the whole thing as
getArgs >>= \a -> readFile (a!!0) >>= writeFile (a!!1) . unlines . sort . lines
but decided that that's exactly the kind of thing that gets Haskell programmers a bad reputation. function Sort-File ($Path, $Destination) {
Get-Content $Path | Sort-Object | Out-File $Destination
}
Granted, shells are probably at an advantage when it comes to file management. I'd think a bash variant would be quite short as well.Aiming for succinctness by using aliases and using redirection instead of cmdlets for writing the file (shorter, but less flexible):
function sf { gc $args[0] | sort > $args[1] }
That's not code anyone should write outside code golfing, though ;-) cat in.txt | sort > out.txt sort in.txt > out.txtsort in.txt > out.txt
cat file | command > out
is the same as command < file > outcat $1 | sort > $2
import sys
open(sys.argv[2], "w").writelines(sorted(open(sys.argv[1]))) sortifile, line and data have to be defined before the loop. ofile could be defined closer to usage, but I think it's much clearer where it is, grouping in and out defs together making it obvious how argv is used for each.
#include <iterator>
#include<vector>
#include<algorithm>
#include<fstream>
using namespace std; // Bad but shorter!
int main(int argc, char** argv) {
ifstream infile(argv[1]);
ofstream outfile(argv[2]);
ifstream_iterator<string> start(infile), end;
vector<string> lines(start, end);
sort(lines.begin(), lines.end());
copy(lines.begin(), lines.end(), ostream_iterator<char>(outfile, "\n"));
} Rebol []
files: map-each n system/options/args [to-file n]
write/lines files/2 sort read/lines files/1It's been a while since I looked at C++ but that statement doesn't apply to me. For example:
for(const auto &i : data) {
ofile << i << std::endl;
}
I have no idea what that's doing or why it makes any sense. If I knew C++ better maybe that wouldn't be the case but, for example, the Ruby example someone else provided is obvious to me (and I don't work with Ruby).It feels there's a lot of telling the machine how you want to do something going on in here (instead of what you want it to do).
I'd be really interested in hearing how this sample differs from a previous C++ implementation.
for (vector<string>::const_iterator it = data.begin(); it != data.end(); ++it) {
ofile << *it << endl;
}
But in this case we're dealing with a vector, so you don't need iterators: for (unsigned i = 0; i < data.size(); ++i) {
ofile << data[i] << endl;
} for (size_t i = 0, iEnd = elems.size(); i < iEnd; ++i)
{
Elem &elem = elems[i];
// deal with elem
}
Of course the new C++11 syntax is king.You probably know something that is similar to Ruby, and that's why you understand it without ever learning it. I bet that you wouldn't understand it if you didn't know any programming language at all.
for(const string &s : data) {
ofile << s << std::endl;
}
which is a lot more clear about what type of thing you're getting out of the vector on each iteration.If data is a vector of, for example, pointers to const char, on each iteration this code will unnecessarily copy each item into a temporary string before printing it. Using auto would avoid this step, regardless of data's type.
Note that the typical non-range-based for loop also omits the vector item type... Is this that much less clear?:
for (int i = 0; i < data.size(); ++i) {
ofile << data[i] << std::endl;
} for (vector<string>::iterator i = data.begin(); i != data.end(); ++i) {
ofile << *i << std::endl;
}
which makes it pretty clear what types we're dealing with. foreach(data, []<class T>(const T & item) {
ofile << item << std::endl;
});
This should eliminate the potential implicit conversion to temp. But I'm not sure it's seriously better than the original range based for with auto.Semantics though.
C++ is adopting some of the properties of scripting languages, but I'm not aware of any implementations that have removed the explicit compile step. I don't think it's really accurate to call C++ scripting as long as that step is still required, and I haven't seen very much interest in taking it out.
And before you complain it's not the same thing, that's basically all a scripting language does. The compilation step is hidden inside the command wrapper.
You have to import the headers, using include guards if your "script" spans multiple files. Any external headers have to be in the header search path, libraries have to be explicitly linked and also be in the linker path, you have to have a makefile or similar in order to manage the compilation complexity.
If you are using, say, python, all you have to do is add the shebang, "import" the desired packages and you are good to go. One has to install the eggs, packages, or whatever the name is beforehand, but after that you can just use them.
Also of note: does more than just C/C++: FORTRAN, Java, Pascal, even assembly; and includes a "realcsh" and "realksh" for that C and kernel REPL you've been craving. Just "apt-get install binfmtc". I test out quick little things in C++ with this all the time.
It is made by Cern and based on Clang
import fileinput, sys
for line in sorted(fileinput.input()):
sys.stdout.write(line)
Advantages over C++:* Fewer import/using lines (5 lines in the C++ version).
* No variable declarations (4 lines in the C++ version).
* Automatic iteration over file or file-like objects is very nice. No need to build a list via getline() and the terribly-named "push_back()" function.
* No "data.begin(), data.end()" parameters to the sort function -- sane defaults, people.
* "for line in file" is so much easier to read than "for(const auto &i : data)".
* Return 0 is implicit. Explicit is better than implicit, I know, but this is a very sane default. If there's an exception, Python won't return 0.
* Better automatic error handling. What does the C++ version print if a file doesn't exist or if there's a read error?
* Thanks to Python's standard library (fileinput module), it automatically handles stdin, multiple input files, etc.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
struct Line
{
string lineData;
operator string() const
{
return lineData;
}
};
std::istream& operator>>(std::istream& str,Line& data)
{
getline(str,data.lineData);
return str;
}
int main(int argc, const char * argv[])
{
ifstream ifile(argv[1]);
ofstream ofile(argv[2]);
vector<string> data;
copy(istream_iterator<Line>(ifile), istream_iterator<Line>(), back_inserter(data));
sort(data.begin(), data.end());
copy(data.begin(),data.end(), ostream_iterator<string>(ofile, "\n"));
return 0;
}
And to inform everyone. Cling as a C++ REPL exists. http://root.cern.ch/drupal/content/clingIt's funny, had the author tweaked the problem just slightly to try make C++ look good by saying that the program should output sorted words instead of lines, you could have deleted the entire Line nonsense. Had the problem been to output sorted, unique words, you could have made the rather elegant:
int main(int argc, const char* argv[])
{
using input = istream_iterator<string>;
using output = ostream_iterator<string>;
ifstream inputfile(argv[1]);
ofstream outputfile(argv[2]);
set<string> words{input(inputfile), input()};
copy(words.begin(), words.end(), output(outputfile, "\n"));
}
But then again, it's not exactly in C++'s favor as a scripting language that copying words is easy, while lines is hard.The thing which (to me) makes a scripting language /better/ for actual scripting, is that it's run from sourcecode.
In unix terms, if the file starts with '#!'
Why? Because I can write a 4 line BASH script which I plonk into /usr/local/bin and it just works. When I want to check why something happened on the filesystem, I can open the script in place, and step through it in the REPL.
No faffing around with trying to figure out where the source code is, no compile/link/whatever...
Of course, while developing something a little more serious in a scripting language, I use a linter+unittests in pretty much the same way as a compiler... but that's besides the point.
Haskell is usually much more concise than C++, but I don't consider it a scripting language. (OK, I could use an interpeted haskell, I suppose... Just as you could use a BBC micro ASM interpreter in a VM... but whatever. It's just silly)
Must be bring your own garbage collector to work day.
Admittedly, even old style C++ with Boost does look a lot like a scripting language (except for the segfaults).
for(const auto &i : data) {
ofile << i << std::endl;
}
The for loop definition there with the auto keyword. The rest has been standard for donkeys years. BOOST_FOREACH(string i, data) {
ofile << i << std::endl;
}I love C++, but let's not make stupid claims.
What error specifically are you looking to see handled that wouldn't be exactly equivalent in your scripting language of choice?
- No need to manually manage memory.
That isn't true at all. You know enough memory management to avoid memory issues in your example. C++11 didn't save you from needing to understand it -- you understand it so avoided needing it.
- Compile time with -O3 is roughly the same as Python VM startup and has to be done only once.
It still requires two separate steps. Also, compile gets slower as the program gets larger, which isn't nearly as true for Python.
There are many sane subsets of C++ that save us from worrying about memory. If you just keep everything on the stack or in an auto_ptr, you should do fine.
The point is practical: is the language as typically used subject to routine "accidental" memory leaks? That's surely true for C, and remains true for most C++ idioms used up until the last few years or so.
It's not true of the kind of RAII style being talked about in the linked article. In that style it's routine to write large projects that literally never call operator delete, and need to resort to an operator new only in rare circumstances (often for compatibility with older APIs).
Modern C++ when used at this level[1] really does have the same kind of casual robustness against leaks and free-memory issues that you expect to see from garbage collected environments. And it's not even hard.
[1] Which is not to say that all contemporary C++ can be written in this model. Obviously if you're doing syscall-level code you'll need to be touching memory (and probably the heap) directly. But that's sort of the point.
If this were true, we would expect to see large C++ codebases without memory-related security vulnerabilities. But the security history of every large C++ codebase that I have seen or heard of says otherwise. I would love it to be true, but I don't think it's a tenable position that C++, even "modern" C++, is memory-safe in practice.
We can argue over whether the C++ deployed in practice is "real" modern C++, but I think that enters into no true Scotsman territory really quickly. The fact is that C++ is not memory-safe in theory and has not been shown to be memory-safe in practice. For example, I know of real security bugs in Firefox that were caused by issues that are not fixed by any "modern" C++ idioms.
OK, we're talking past each other. The linked article and my point was about C++'s suitability for achieving software quality in tasks that are traditionally done by "scripting" languages. Security analysis is an entirely different world, and I tend to agree that other languages have a head start there as far as memory safety.
But that said, "memory safety" is hardly a big contributor to the overall vulnerability list. C++ is much less used on web backends, and it's likewise true that almost no large web service codebase exists without non-memory-related security vulnerabilities. I don't know if there are any deployed Rust codebases of this size, but I'd expect them to have their share of whoppers too.
C++11 has many nice new things, if you are not familiar with it, I recommend starting also on the wiki: https://en.wikipedia.org/wiki/C%2B%2B11
from sys import argv
open(argv[2], 'w').writelines(sorted(open(argv[1])))
compile time with -O3 is roughly the same as Python VM startup and has to be done only once
So I think the OP argues that there is no need for a C++ interpreter because compiling C++ code is as fast as starting a Python VM.
C++ has matured to the point where it has 95% of what a scripting language needs. It wouldn't be hard to write a thin wrapper that provided the final 5%, and it would come as a welcome convenience to programmer who are used to working with the C++ libraries.
Oh. Wait a moment. It's already been done. It's called Lua. Ho hum.
If you need access to a native library that isn't exposed through any other tool, sure, then writing a C++ tool is an acceptable route.
compile time with -O3 is roughly the same as Python VM startup and has to be done only once
It's a non-scripting language hassle to have to compile. Of course, you just need a little front-end to automatically compile if needed for you. IIRC Perl actually does this.But I like his emphasis on large standard libraries, enabling compact scripts, esp string processing, and memory managed. WHy couldn't you do this trick with C (i.e. compile & run)? It's mainly libraries, though memory management isn't natural. Actually, I could believe that many scripting languages actually started like that, but shifted to their own syntax asap.
This trick can also be done with java, by keeping a server in the background to run it to cheat the VM startup tax (and auto-compiling as needed). Java verbosity is a problem, but you can write C-like code in Java. The biggest problem is the detail of Java libraries - they give you a lot of control, but a scripting language should give you less control, in return for quick functionality (like unix `sort`).
E.g.
import Data.List
main = interact (unlines . sort . lines)
On the other hand, by modularizing the code down into libraries, and generally using incremental compilation, after an initial 'full build', minor builds during development are not too slow.
An example of my problem with C++ is, writing a function in a shared library, which is meant to return a class from the standard library say vector<string>, to the program that calls it is very unwise.
Can you imagine if your Python modules couldn't return objects from the standard library?
This is because the shared library and calling program might have been compiled against a different version of the standard library, and also because the 'flattened names', used to refer to members of a class are not uniform between compilers / compiler versions. You can often get away with stuff on linux, because all the software is compiled in the same environment, but build once run anywhere? No.
This is turning into a bit of a rant. I like C++, but it has so many imperfect, jagged edges, enough to surprise programmers after 10 or 20 years. There is still a lot left to fix.
Lack of tooling was another one, but with libclang tons of good tools are coming.
The biggest thing about a real scripting language is that I have one step to go from edit to run.