176
\$\begingroup\$

In this challenge, users will take turns completeing three fairly simple coding tasks in programming languages that are allowed to be progressively older.

The first answer must use a programming language that was made in the year 2015. Once there is at least one answer from a 2015 language, answers may use programming languages that were made in 2014. Similarly, answers that use languages from 2013 are not allowed until there is at least one 2014 answer.

In general, the use of a programming language from the year Y is not allowed until an answer using a language from the year Y+1 has been submitted. The only exception is Y = 2015.

Finding Your Language's Year

To answer this question, you must know the year your programming language was "made in". This is, of course, a subjective term; some languages were developed over the course of multiple years, and many languages are still being upgraded every year. Let the year a language was "made in" be the first year an implementation for that language appeared in the general public.

For example, Python was "made in" 1991, though its development had been in progress since 1989, and version 1.0 wasn't released until 1994.

If this year is still subjective, just use your common sense to choose the most appropriate year. Don't get bogged down in slight disagreements about year choices. Please provide a link to a source that says when your language was made.

Different versions or standards of a programming language (e.g. Python 1, 2, 3) are counted as the same language with the same initial year.

So, unless your language's year is 2015, you can only submit your answer once an answer has been submitted whose language's year is the year just before yours.

If a valid answer with the same year as yours already exists, then you may answer. It doesn't matter if your language was developed earlier or later in the year.

Tasks

You must complete Tasks 1 through 3. Task 0 is optional.

These tasks were more or less chosen to correspond to three important aspects of programming: providing output (Task 1), looping (Task 2), and recursion (Task 3).

Task 0 - Language History (optional)

Write at least a paragraph explaining the history of your chosen programming language: who developed it, why, how, etc. This is especially encouraged if you personally were around when the language came into being, and maybe even played a part in its development. Feel free to relate personal anecdotes about the effect the language had on you or your job, or anything like that.

If you're too young to know much about the history of your language without a lot of research, consider leaving a note to older users that says they can edit your post and add in some first-hand history.

Task 1 - "Hello, World!" Variant

Write a program that prints

[language name] was made in [year made]!

to your language's standard output area (stdout for most recent languages).

For example, if the language was Python, the output would be:

Python was made in 1991!

Task 2 - ASCII Art N

Write a program that lets the user enter in an odd positive integer (you may assume the input is always valid), and prints out an ASCII art letter N made using the character N.

If the input is 1, the output is:

N

If the input is 3, the output is:

N N
NNN
N N

If the input is 5, the output is:

N   N
NN  N
N N N
N  NN
N   N

If the input is 7, the output is:

N     N
NN    N
N N   N
N  N  N
N   N N
N    NN
N     N

The pattern continues on like this. The output may contain trailing spaces.

Task 3 - GCD

Write a program that lets the user enter in two positive integers (you may assume the input is always valid), and prints their greatest common divisor. This is defined as the largest positive integer that divides both numbers without leaving a remainder. It can be readily calculated using the Euclidean algorithm.

Examples:

8, 124
12, 84
3, 303
5689, 21
234, 8766

You may use a built in function but try finding out if it was there in the first version of your language. If not, try not using it.

Rules

  • You may answer multiple times, but each new answer must use a language made at least 5 years before the language in your last answer. So if you answered with a 2015 language, you couldn't answer again until 2010 languages are allowed. If you start with a 2010 answer, you can't make a 2015 answer your second answer because 2015 is not before 2010.
  • If possible, write your code so that it would have worked in the very first version of your language (or as old a version as possible). (This is not a requirement because finding old compilers/interpreters for some languages may be difficult.)
  • Refrain from posting a language that has already been posted unless the posted answer has significant errors or you have a very different way of completing the tasks.
  • Golfing your code is fine but not required.
  • A trailing newline in the output of any program is fine.
  • For tasks 2 and 3, all input values below some reasonable maximum like 216 should work (256 at the very least).
  • Your language must have existed before this question was posted.
  • Very old programming languages may have different forms of input and output than what we think of today. This is fine. Complete the tasks to the best of your ability in the context of your language.

Scoring

Your submission's score is:

upvotes - downvotes + (2015 - languageYear) / 2 

Thus, 0.5 is added to the vote count for every year before 2015, giving the advantage to older languages. The submission with the highest score wins.

Answer List

The Stack Snippet below lists all the valid answers according to their language year.

You must start your post with this Markdown line to ensure it is listed correctly:

#[year] - [language name]

For example:

#1991 - Python

The language name may be in a link (it will be the same link in the answer list):

#1991 - [Python](https://www.python.org/)

Answers that don't follow this format, or have a year that is not allowed yet, or come from a user that already answered in the last 5 years are marked as invalid.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><script>$(function(){function e(e,r){var a="https://api.stackexchange.com/2.2/questions/48476/answers?page="+e.toString()+"&pagesize=100&order=asc&sort=creation&site=codegolf&filter=!YOKGPOBC5Yad160RQxGLP0r4rL";$.get(a,r)}function r(e){if(e.items.forEach(function(e){var r=e.link,a=e.owner.display_name,i=e.body.match(/<h1\b[^>]*>(\d{4}) - (.*?)<\/h1>/);if(i&&i.length>=3)var h=parseInt(i[1]),u=i[2];h&&u&&n>=h&&h>=t&&(!d.hasOwnProperty(e.owner.user_id)||d[e.owner.user_id]-h>=p)?(d[e.owner.user_id]=h,h==t&&--t,o.hasOwnProperty(h)||(o[h]=[]),o[h].push({language:u,user:a,link:r,score:e.score+(n-h)/2})):s.push(' <a href="'+r+'">'+a+"</a>")}),e.has_more)runQuery(++a,r);else{for(var i=n,h=[];o.hasOwnProperty(i);){for(var u=$("<tr>").append($("<td>").text(i.toString())),l=$("<td>"),c=$("<td>"),g=$("<td>"),f=0;f<o[i].length;f++){var v=o[i][f];l.append(v.language),c.append($("<a>").html(v.user).attr("href",v.link)),g.append(v.score),f+1<o[i].length&&(l.append("<br><br>"),c.append("<br><br>"),g.append("<br><br>"))}u.append(l).append(c).append(g),h.push(u),--i}$("#answers").find("tbody").append(h),s.length>0?$("#invalid").append(s):$("#invalid").remove()}}var a=1,n=2015,t=n-1,p=5,o={},s=[],d={};e(1,r)})</script><style>html *{font-family: Helvetica, Arial, sans-serif;}table{border: 4px solid #a4a; border-collapse: collapse;}th{background-color: #a4a; color: white; padding: 8px;}td{border: 1px solid #a4a; padding: 8px;}div{font-size: 75%;}</style><table id='answers'> <tr> <th>Year</th> <th>Language</th> <th>User (answer link)</th> <th>Score</th> </tr></table><div id='invalid'><br>Invalid Answers:</div>

\$\endgroup\$
16
  • 2
    \$\begingroup\$ This should help. \$\endgroup\$
    – swish
    Apr 6, 2015 at 9:10
  • 27
    \$\begingroup\$ Wikipedia has a list for everything: this one for non-esoteric languages by year. \$\endgroup\$
    – Sanchises
    Apr 6, 2015 at 12:30
  • 2
    \$\begingroup\$ Should Task 3 actually use recursion or is it enough that it produces the correct result? If I need to write my own GCD function I usually just use a loop but I wrote a recursive one specially for this challenge. There are many submitted answers that just use a loop. \$\endgroup\$
    – CJ Dennis
    May 3, 2015 at 2:51
  • 5
    \$\begingroup\$ I feel like making a second account just to get us past 1971. \$\endgroup\$
    – marinus
    May 5, 2015 at 10:49
  • 6
    \$\begingroup\$ If we can get it back to 1952, I have someone spinning up a historic machine that could do 1951 (Pegasus) solutions and test them! \$\endgroup\$ May 19, 2015 at 18:19

101 Answers 101

9
\$\begingroup\$

1993 - Batch

My reason for suggesting that Batch was created in 1993 is explained in a question I posted at StackOverflow: https://stackoverflow.com/questions/29484750/when-was-batch-created

Hello World.bat

@echo off
echo Batch was created in 1993!
pause

I added the pause at the end with the assumption that it would be run by 'double-clicking' the file in explorer, as opposed to called from the command line (otherwise the CMD window would instantly close when the script has completed). My other two scripts assume they are being called from the command line, as they both require input from stdin.

ASCII N.bat

@echo off
setLocal enableDelayedExpansion

for /l %%a in (1,1,%1) do (
    set "l="
    for /l %%b in (1,1,%1) do (
        set "c= "
        if %%b==1 set c=N
        if %%b==%1 set c=N
        if %%b==%%a set c=N
        set l=!l!!c!
    )
    echo !l!
)

This script uses the fact that the crossing character (that is, the line that travels diagonally from top left to bottom right in the character N) is always populated at position y in the row - where y is the current column (if %%b==%%a set c=N). Then the first and last character in each row is always populated. The first for loop defines rows, and the inner for loop defines columns.

GCD.bat

@echo off
setLocal enableDelayedExpansion

for %%a in (%1, %2) do (
    set "l%%a="
    for /l %%b in (1,1,%%a) do (
        set /a a=%%a %% %%b
        if !a!==0 set l%%a=!l%%a! %%b
    )
)

for %%c in (!l%1!) do for %%d in (!l%2!) do if %%c==%%d set h=%%c

echo !h!

When doing anything even remotely complicated in Batch, there always tends to be a lot of nested for loops. The first set of loops creates two lists which contain every number from 1 to n which divides evenly into the n, where n is either of the inputted values. The second loops just compare each value in one list to each value in the other, until the highest value that exists in both lists is found. Just a note that Batch doesn't actually have arrays, so all I have done is created a bunch of variables with uniform names.

Hacker Aesthetic

\$\endgroup\$
2
  • 3
    \$\begingroup\$ Some people's batch skills amaze me. \$\endgroup\$ Apr 16, 2015 at 1:53
  • \$\begingroup\$ @kirbyfan64sos Nice of you to say :) \$\endgroup\$
    – unclemeat
    Apr 16, 2015 at 3:28
9
\$\begingroup\$

1984 - Standard ML

Standard ML is a descendant of the ML programming language. It's a functional programming language with strong, compile-time type checking and inference.

I work with Haskell a lot, and comparing it to that, Standard ML seems less pure, and definitely lacks a lot of the nice syntactic sugar that Haskell has. Nonetheless, the type system looks neat, and code written in it looks elegant.

(I, too, learned this language just to answer the challenge, and because I've been interested in older functional languages like ML and Miranda. If you're a Standard ML expert, and notice something in this code looks really unidiomatic, feel free to point it out.)

Task 1

print "Standard ML was made in 1984!\n";

The print function prints the given string to standard output. Not much to say here.

Task 2

fun asciiArt (s : int) : string =
  let
    fun line n = implode (List.tabulate (s,
      fn i => if i = 0 orelse i = n orelse i = s - 1
                then #"N"
                else #" "
    ))
  in
    String.concatWith "\n" (List.tabulate (s, line))
  end;

fun readInt h =
  Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) h);

print "Size: ";
val s = readInt TextIO.stdIn;

print (asciiArt s);

To get some asciiArt of size s, we define a helper function that gets us the nth line, then generate a bunch of lines and concatenate them with newlines. We read a number from TextIO.stdIn and print the corresponding ASCII art N.

The List.tabulate function is basically: tabulate (n, f) = [f 0, f 1, ... f (n-1)].

Task 3

fun gcd (a : int) (b : int) : int =
  if b = 0 then a else gcd b (a mod b);

fun readInt h =
  Option.valOf (TextIO.scanStream (Int.scan StringCvt.DEC) h);

print "First number: ";
val a = readInt TextIO.stdIn;
print "Second number: ";
val b = readInt TextIO.stdIn;

print ("The GCD of " ^ Int.toString a ^ " and " ^ Int.toString b ^
       " is " ^ Int.toString (gcd a b) ^ ".\n");

We implement the Euclidean GCD algorithm recursively, read two numbers, and print the result. There's no built-in GCD function, it seems. ^ is an interesting choice of string concatenation operator.

\$\endgroup\$
2
  • \$\begingroup\$ I think your gcd fails to show off SML's powerful module system. The same algorithm should work in any Euclidean domain. You can write a GCD functor that takes the domain structure as an argument. \$\endgroup\$
    – dfeuer
    Mar 14, 2019 at 19:17
  • \$\begingroup\$ @dfeuer I encourage you to post your own answer. \$\endgroup\$
    – Lynn
    Mar 14, 2019 at 20:52
9
\$\begingroup\$

1975 - Scheme

Scheme is one of the older and most successful dialects of the LISP family of languages. It predates Common Lisp, Emacs Lisp, and most others still in use.

Its philosophy is based on minimalism and extensibility.

The basic language is made of a minimal set of syntax rules; 12 "fundamental forms," or keywords that need to be specifically implemented by the runtime, such as if and define; and 11 "library forms," keywords that are part of the language definition, but can be internally implemented using the fundamendal forms.

The minimalism is coupled with extreme extensibility. Scheme's macro system is arguably the most advanced hygienic, Turing-complete pre-processor of all programming languages. It is to C's macro preprocessor as a Ferrari is to a soap box!

Scheme's unique philosophy and its hacker-friendly minimal footprint have always attracted many thinkers and tinkerers alike. 40 years after its inception we have dozens of implementations, running on all sorts of platforms and using all manner of compiler or interpreter technologies, including very bizarre but effective ones. Scheme is an excellent testbed for programming language ideas, but it is also a great language for everyday programming.

Its syntax may appear strange to those unfamiliar with LISP, but it has many advantages, starting with its regularity. Every function, operator, and control structure of the language takes the same form: (name arguments...) where both the name and the arguments may be nested expressions. This simplicity and regularity makes Scheme the ideal language for teaching programming to novice students, as demonstrated by the success of Structure and Interpretation of Computer Programs by MIT Press. Citing Wikipedia:

Before SICP, the introductory courses were almost always filled with learning the details of some programming language, while SICP focuses on finding general patterns from specific problems and building software tools that embody each pattern.

Hello World!

(begin
  (display "Scheme was made in 1975!")
  (newline))

ASCII Art N

(let ((n (read)))
  (let row ((r 1))
    (let col ((c 1))
      (display (if (memq c (list 1 n r))
                   "N" " "))
      (if (< c n)
          (col (+ c 1))
          (newline)))
    (if (< r n)
        (row (+ r 1)))))

GCD

(let gcd ((m (read))
          (n (read)))
  (if (zero? n)
      m
      (gcd n (modulo m n))))
\$\endgroup\$
9
\$\begingroup\$

1995 - Java

History

Java is a general-purpose language that runs on a large variety of systems, from web servers to smart phones and disc players. Development started in 1991 at Sun Microsystems, version 1.0 was released in 95. In 99, version 1.2 was renamed to "Java 2". Java is very verbose and thus unsuitable for code golfing, which hasn't stopped some from trying. It also has a reputation for yielding over-engineered solutions and being generally clumsy. Basically, just like this text.

Hello World

class M{public static void main(String[]a){System.out.print("Java was made in 1995");}}

(golfed as much as possible)

ASCII N

public class Main {
    public static void main (String[] args) {
        int n = Integer.parseInt(args[0]);
        for (int i = 0; i < n; i++) {
            System.out.print('N');
            for (int j = 1; j < n-1; j++) {
                System.out.print(j == i ? 'N' : ' ');
            }
            System.out.println('N');
        }
    }
}

GCD

public class Main {
    public static void main (String[] args) {
        int a = Integer.parseInt(args[0]);
        int b = Integer.parseInt(args[1]);
        System.out.printf("GCD of %d and %d: %d%n", a, b, gcd(a, b));
    }

    public static int gcd(int a, int b) {
        if (b > a) return gcd(b, a);
        else if (b == 0) return a;
        else if (a == 0) return b;
        else return gcd(b, a%b);
    }
}
\$\endgroup\$
4
  • 2
    \$\begingroup\$ +1 for applying Java coding style to the history paragraph ;) \$\endgroup\$
    – DLosc
    Apr 15, 2015 at 19:23
  • \$\begingroup\$ I would still use % instead of - in the last gcd call. \$\endgroup\$ Apr 17, 2015 at 20:59
  • \$\begingroup\$ "golfed as much as possible", lol. no. Remove the space after String[], and change println to print. \$\endgroup\$
    – mbomb007
    Apr 21, 2015 at 15:45
  • \$\begingroup\$ fixed, also renamed args to a \$\endgroup\$
    – Cephalopod
    Apr 22, 2015 at 18:49
8
\$\begingroup\$

1997 - Fortran 95

I am a bit late with this answer, since Fortran 95 wasn't published until 1997. Oh well. From Wikipedia:

Fortran 95, published officially as ISO/IEC 1539-1:1997, was a minor revision, mostly to resolve some outstanding issues from the Fortran 90 standard. Nevertheless, Fortran 95 also added a number of extensions, notably from the High Performance Fortran specification.

“Hello, World!”

program say_my_name
  print '(A)', "The Fortran 95 standard was published in ... 1997."
end program say_my_name

ASCII art “N”

For the ASCII art task, Fortran's formatted i/o is actually quite handy:

program paint_N
  integer            :: N, i
  character(len=500) :: fmt

  read*, N

  do i=1,N
     write(fmt, "('(', 2(A, ',', 'T', I0, ','), A, ')')") &
          "'N'", i, "'N'", N, "'N'"
     print fmt
  end do
end program paint_N

Greatest common divisor

For the GCD task I chose the binary method. The bitwise intrinsics (IAND, IOR, ISHFT), as well as user-defined pure functions, were only introduced with Fortran 95. Also, I took the liberty of adding a loop so you can compute more than one GCD per execution. The algorithm is a straightforward translation of http://en.wikipedia.org/wiki/Binary_GCD_algorithm#Iterative_version_in_C.

program binary_GCD_algorithm
  integer :: a, b

  do
     read(*,*, END=1) a, b
     print*, gcd(a,b)
  end do

1 continue

contains

  pure integer function gcd(a, b)
    integer, intent(in) :: a, b
    integer             :: shift, u, v, t

    u = a
    v = b

    if (u == 0) then
       gcd = v
    else if (v == 0) then
       gcd = u
    else
       shift = 0
       find_shift: do while (iand(ior(u, v), 1) == 0)
          u = ishft(u, -1)
          v = ishft(v, -1)

          shift = shift+1
       end do find_shift

       halve_u: do while (iand(u, 1) == 0)

          u = ishft(u, -1)
       end do halve_u

       reduce_v: do
          halve_v: do while (iand(v, 1) == 0)

             v = ishft(v, -1)
          end do halve_v
          
          swap: if (u > v) then
             t = v
             v = u
             u = t
          end if swap

          v = v - u

          if (v == 0) exit reduce_v
       end do reduce_v

       gcd = ishft(u, shift)
    end if
  end function gcd
end program binary_GCD_algorithm
\$\endgroup\$
3
  • \$\begingroup\$ Just in case you missed the note, posting versions of programming languages is discouraged unless the version is significantly different than its predecessors. I see that your code in your Fortran 90 answer does offer different task solutions, which is good, but I'm no Fortran expert and can't say how much it's really worth having both versions. I'd say to refrain from posting any more Fortran versions until the original Fortran. \$\endgroup\$ Apr 16, 2015 at 23:40
  • \$\begingroup\$ @Calvin'sHobbies Not to worry, I won't be tackling any older versions, and I don't know what the 2003/2008 versions would have to add. It is sometimes difficult to say what is a “different language”, and I would argue that at least Fortran pre-90 (fixed format) and post-90 are “different”, but not really 90 and 95, I admit. If you prefer, I can delete one of the answers. Neither of them are needed for the chain. \$\endgroup\$
    – xebtl
    Apr 17, 2015 at 11:42
  • \$\begingroup\$ To be honest, after seeing a “C++98” answer, I thought Fortran 95 should qualify as well, and the year was about right. Then I realized that 90/95 could actually make difference for the GCD task. \$\endgroup\$
    – xebtl
    Apr 17, 2015 at 11:43
8
\$\begingroup\$

1995 - PHP

PHP began life as a project of Rasmus Lerdorf, intended to help him manage his personal homepage. The original name was Personal Home Page Tools, later changed to Personal Home Page/Forms Interpreter (PHP/FI). Lerdorf never intended to create a programming language, but things snowballed, a development team was formed, and the rest is history. PHP is now used extensively for server-side scripting as one of the options for the P in LAMP (or WAMP); more-recent versions have added support for command-line and client-side GUI applications as well.

Syntax is closest to Perl, with $ used for variables and implicit casting between strings and numbers. Like JavaScript, PHP has been criticized for its ad-hoc construction, which resulted in numerous weird quirks and inconsistencies; nevertheless, I find it fairly easy to work with in practice. The PHP language reference is always helpful.

Task 1

<?php echo "PHP/FI was made in 1995!" ?>

(The name was changed to the recursive acronym "PHP: Hypertext Preprocessor" in 1997.)

Task 2

<?php
$size = $HTTP_GET_VARS['size'];
for($i = 0; $i < $size; $i++) {
    for($j = 0; $j < $size; $j++) {
        if($j == $i || $j == 0 || $j == $size - 1) {
            echo 'N';
        } else {
            echo '&nbsp;';
        }
    }
    echo '<br>';
}
?>

Since CLI support was not in the original PHP, it seemed appropriate to write these examples as web pages with input from URL parameters. I understand that $HTTP_GET_VARS used to be the way to do that; however, it is now deprecated in favor of $_GET, which is what I used to test my code (on PHP 5.5). The result looks best if you wrap the PHP in a <pre> tag.

Task 3

<?php
$a = $HTTP_GET_VARS['a'];
$b = $HTTP_GET_VARS['b'];
while($a > 0) {
    $tmp = $b;
    $b = $a;
    $a = $tmp % $a;
}
echo $b;
?>

Putting all three in the same file (and changing $HTTP_GET_VARS to $_GET as mentioned above) gives the following result:

PHP three tasks

\$\endgroup\$
3
  • \$\begingroup\$ Point of pedantry: the first version was actually called "PHP Tools" (for "Personal Home Page Tools"); "PHP/FI" was the name at the time of 2.0, just before it got rewritten into something recognisable. See php.net/history.php It would be interesting to get some old versions from the museum and try to write the code in those (the syntax is very different!) \$\endgroup\$
    – IMSoP
    Apr 19, 2015 at 18:24
  • \$\begingroup\$ @IMSoP Point taken--I will add a note. Re: older versions, I almost downloaded one, but decided it wasn't worth the trouble of (re)configuring a web server to run it. \$\endgroup\$
    – DLosc
    Apr 20, 2015 at 15:07
  • \$\begingroup\$ You missed an opportunity to do the screenshot in a 1995 browser :) \$\endgroup\$
    – user61264
    Nov 29, 2016 at 12:55
8
\$\begingroup\$

1990 - J

Task 1: Hello World!

'J was made in 1990!'

This reflects the typical use of J: in an REPL, this would echo the string back at you. Not very useful in general, but exactly what we want here.

Task 2: ASCII N

' N' {~ (1) 0 _1}"1 =@i.

What we do here might be a bit different other languages would do. We start by creating an identy matrix of a given size: =@i.. Then we set the first and last collumn to be 1: (1) 0 _1}"1. (If you were to name everything, one might name it as 1 (first, last) set collumns, or something like that). Then, we use these values as indices to the string ' N', 0-indexed, so that we get the wanted result. Again, as this returns a string(matrix), this is printed to screen.

This is an anonymous function, so we could assign it to a variable (or not, but it is convenient), and run it:

    f =: ' N' {~ (1) 0 _1}"1 =@i.
    f 5
N   N
NN  N
N N N
N  NN
N   N

Task 3: GCD

There is just a builtin function for this: +.. However, since this is not fun in the slightest, we are going to define our own function:

<./&.:(_ q: ])

This also reflects the different attitude that is often used in J, as opposed to Von-Neumann languages. First, we aquire a table of all prime exponents of the entire list of numbers: (_ q: ]). Then, we find the minimum of every collumn: <./. Lastly, &.: applies the inverse of (_ q: ]) to the result, which gives the GCD.

\$\endgroup\$
8
\$\begingroup\$

1974 - CLU

CLU was created at MIT by Barbara Liskov. It's never widely used, but it influenced many important languages.

The development of CLU began in 1974, and the first version was released in 1975. But we need a language for 1974.

I've never used CLU, and I can't find a compiler for linux or windows, so I didn't test my code. Feel free to edit my post if you find anything wrong.

Task 1

start_up = proc ()
           po: stream := stream$primary_output ()
           stream$putl (po, "CLU was made in 1974!")
           end start_up

Task 2

ascii_art_n = proc (n: int)
              po: stream := stream$primary_output ()
              for i: int in int$from_to (1, n) do
                for j: int in int$from_to (1, n) do
                  if j = 1 | j = i | j = n
                    then stream$putc (po, 'N')
                    else stream$putc (po, ' ')
                    end
                  end
                stream$putc (po, '\n')
                end
              end ascii_art_n

Task 3

CLU supports multiple assignment, which is known as parallel assignment in nowaday languages.

gcd = proc (m, n: int) returns (int)
      while n > 0 do
        m, n := n, (m // n)
        end
      return (m)
      end gcd
\$\endgroup\$
4
  • 3
    \$\begingroup\$ It looks like it's Python's granddad. \$\endgroup\$
    – marinus
    Apr 25, 2015 at 9:13
  • \$\begingroup\$ Try clu2c. \$\endgroup\$ Apr 25, 2015 at 22:18
  • \$\begingroup\$ Nevermind; link's down. Oh well. +1 because you seriously saved all our hinds from 1974! \$\endgroup\$ Apr 26, 2015 at 0:53
  • 1
    \$\begingroup\$ Actually, there's a working version here...but the build system's badly broken. \$\endgroup\$ Apr 26, 2015 at 1:01
8
\$\begingroup\$

1971 - dc

Thanks to marinus for recommending dc -- this is a little RPN calculator released with Unix V1 in 1971.

Task 1

[dc was made in 1971!
]P

[] are string delimiters; apparently you can just include a raw newline in a string! It gets pushed to the stack, P prints it.

Task 2 (ASCII art)

# Replace top of stack with string N.
[sv[N]]sN

# Line loop
[[ ]
 LxdSx 1     =N
 LxdSx ls    =N
 LxdSx LydSy =N P
 Lx 1- dSx 0<F]sF

# Ascii art loop
[ls Sx lFx 10P
 Ly 1- dSy 0<G]sG

# Ask input
? dss Sy lGx

My eyes! dc has no good looping construct, but we can assign some code in a string to a register, say F, and then call it recursively based on some condition, e.g. =F.

We build up two looping 'subroutines' of this form -- F and G -- that run some code repeatedly, decrementing the number in some register until it hits zero. Then we use these registers (x and y -- LxdSx peeks a register value) to decide whether we want to print a space or an N.

There doesn't seem to be a pop command -- sv pops the top of stack and stores it in a 'junk' register, v.

Task 3 (GCD, from wikipedia)

??[dSarLa%d0<a]dsax+p

This is Euclid's algorithm, implemented with the same approach to loops.

\$\endgroup\$
8
\$\begingroup\$

1970 - Forth

Try it here

Forth is a relatively easy-to-learn imperative and stack-based programming language. Forth was created by Charles Moore and Elizabeth Rather from a system that had been in development by Charles Moore starting in 1968. They improved and ported Forth to multiple systems over the next decade.

Forth was originally titled "FOURTH", but file names were limited to five characters on the IBM 1130 operating system, so it was named "FORTH".

Forth is written in "reverse Polish notation," which is also known as "postfix" notation. The language is extensible, meaning the user can define their own commands (called "words"), as shown below. Historically, all words would be uppercase, though now this is not a requirement.

Task 1

I define a word called year that prints the string. The space after ." is required, but will not be printed.

: year ." Forth was made in 1970!" ;

Task 2

I define a word called printn that prints the ascii 'N' as required. I also extended the functionality to allow even numbers as well, so that any integer greater than zero can be entered. (It displays nicely only up to about 90 or so using the given link.) Note that the indentation is purely for readability, though it can be typed and run this way as well.

: printn 
    dup 2 > if
        dup 0 do 
            ." N" dup 1- 1 do 
                I J = if ." N" 
                else space 
                then 
            loop 
            ." N" cr 
        loop 
    else 
        dup 2 = if ." NN" cr ." NN" cr 
        else ." N" cr 
        then
    then
    drop ;

Task 3

I define a simple word gcd that returns the greatest common divisor of two integers on the stack.

: gcd begin ?dup while swap over mod repeat ;

Run all three tasks with carriage returns (new lines) between their outputs like this:

year cr cr 
5 printn cr
18 12 gcd . 
\$\endgroup\$
5
  • 4
    \$\begingroup\$ Hmph. Yesterday I learned that weird language just to get this challenge going again, only to find out it was actually the wrong year (1970, not 71) so I deleted my answer to wait until someone would eventually post 1971. Now I come back, and there you are, also with a Forth submission! If I'd known people would so be queueing up (or should I say, stacking up) for Forth... \$\endgroup\$ May 7, 2015 at 1:25
  • \$\begingroup\$ @leftaroundabout I posted in the comments one week ago that I was going to do Forth for 1970. I've had my answer coded since a week before that, waiting to be posted at the right time. Also, I can't see your deleted answer, obviously. codegolf.stackexchange.com/questions/48476/… \$\endgroup\$
    – mbomb007
    May 7, 2015 at 15:38
  • \$\begingroup\$ @leftaroundabout Plus, it's not that weird, and if you'd even looked at the wikipedia article or the timeline ahead of time (or my comment), you would have known it was 1970. \$\endgroup\$
    – mbomb007
    May 7, 2015 at 15:42
  • \$\begingroup\$ Gee. Normally I read every single comment floating around a question with 50+ answers, how could I miss yours. Also, I never ever post comments that include some sarcasm to go with a mediocre joke about some particular language's characteristics. \$\endgroup\$ May 7, 2015 at 15:48
  • 1
    \$\begingroup\$ @leftaroundabout Well, I read it as an upset-sounding comment. \$\endgroup\$
    – mbomb007
    May 7, 2015 at 15:51
8
\$\begingroup\$

1972 - MUSL

In 1972 Manchester University first commissioned their MU5 computer system. The operating system for that computer was called MUSS (Manchester University Software System) and the language MUSL (Manchester University Systems Language) was created to implement that software.

The MUSL language inherited features from Atlas Autocode, Algol 68, Pascal, BCPL and was specifically designed for the implementation of portable operating systems. It was interesting to note that this development took place at the same time as C was being developed for unix. The MUSL compiler was developed using a parser generator called SYNTAB, used an intermediate code generator called MUTL (Manchester University Target Language) and a portable virtual machine code called MUBL (Manchester University Binary Language). MUTL was basically a JIT compiler as we would see it today. Several language compilers targeted MUTL including Fortran, Cobol, Algol, Pascal and so on.

The MUSL compiler was interesting to work with as it only had about 8 error messages. It just flagged "Lexical", "Syntax", "Semantics", "Type" and left it to the programmer to work out where the fault lay!

Although MUSL programs could be written in the normal source form, they were generally expressed in a tool called FLOCODER which graphically represented the code and permitted more than one concrete representation of the algorithm to enable implementation in multiple languages or on multiple platforms from the same file, including embedded documentation. The example MUSL programs are therefore expressed in both the orthodox manner as a code listing and also illustrated in FLOCODER formats, which is how they would have been prepared.

There are MU5 emulators being developed which may eventually run a MUSS system, but at present the code cannot be executed. MUSS (and hence MUSL) was not just implemented on the MU5 but was available on PDP11, VAX, ICL1900, Computervision CDS-4000 CAD/CAM system, MC68000 and several others besides. There may be one of these still running in a museum somewhere!

A brief bibliography:

  • Ibbett, R.N. & Capon, P.C. (1978) "The Development of the MU5 Computer System", Communications of the ACM, pp 13-24.
  • Morris, D & Ibbett, R.N. (1979) "The MU5 Computer System" The Macmillan Press.
  • Ibbett, R.N. (1999) "The University of Manchester MU5 Project" IEEE Annals of the History of Computing, Vol. 21, No1, pp 24-33.
  • Barringer, H., Capon, P.C. & Phillips, R. (1979) "The Portable compiling systems of MUSS", Software Practice and Experience, Vol 9, No.8, pp.645-655.

Task 1

The MUSL:

MODULE HELLO
:: THE I/O LIBRARY BELONGS TO MUSS - NOT MUSL
:: THE FOLLOWING NOTATION GENERATES A POINTER TO A BYTE VECTOR
CAPTION(%"MUSL WAS MADE IN 1972$L");
*END

As a FLOCODER file:

@TITLE HELLO
@COL 1S-2R-3F
@FLOW 1-2-3
@BOX 1.0
A Hello World Program in MUSL
@BOX 1.1
MODULE HELLO
@BOX 2.0
We call the MUSS CAPTION function
with a pointer to a constant byte array
containing the newline character
@BOX 2.1
CAPTION(%"MUSL WAS MADE IN 1972$L");
@BOX 3.0
and exit
@BOX 3.1
*END
@END

As seen:

Hello in Flocoder

Task 2

In MUSL:

MODULE ASCII
:: IN MUSL ALL TYPES MUST ALSO BE SIZED
INTEGER32 N, I, J;
IN.I() => N;
FOR I <> N DO
 FOR J <> N DO
  IF J = 1 ! J = I ! J = N THEN
   OUT.CH("N");  :: AGAIN I/O IS MUSS
  ELSE
   OUT.CH(" ");
  FI
 OD
 NEW.LINES(1);
OD
*END

In FLOCODER source:

@TITLE ASCII
@COL 1S-2R-3R-4R-5R-6T-7R-9R-10R-11R-12F
@COL 8R
@ROW 7-8
@FLOW 1-2-3-4-5-6FALSE-7-9-10-11-12
@FLOW 6TRUE-8-9
@BOX 1.0
Program to write ASCII Art
@BOX 1.1
MODULE ASCII
@BOX 2.0
Declare some 32 bit integers.
There is no default size for
arithmetic types
@BOX 2.1
INTEGER32 N, I, J;
@BOX 3.0
Use MUSS library IN.I 
To read an integer
@BOX 3.1
IN.I() => N;
@BOX 4.0
Iterate for N Rows
@BOX 4.1
FOR I <> N DO
@BOX 5.0
Iterate for N Columns
@BOX 5.1
 FOR J <> N DO
@BOX 6.0
Test if First, middle or last column
@BOX 6.1
  IF J = 0 ! J = I ! J = N-1
@BOX 8.0
Output a letter N
using MUSS library OUT.CH
@BOX 8.1
   OUT.CH("N"); 
@BOX 7.0
Output a space
using MUSS library OUT.CH
@BOX 7.1
   OUT.CH(" ");
@BOX 9.0
End of Column loop
@BOX 9.1
 OD
@BOX 10.0
Output end of line
using MUSS library NEW.LINES
@BOX 10.1
 NEW.LINES(1);
@BOX 11.0
End of Row loop
@BOX 11.1
OD
@BOX 12.0
All done
@BOX 12.1
*END

As seen:

ASCII art in FLOCODER

Task 3

In MUSL form:

MODULE GCDEX
PSPEC GCD(INTEGER32, INTEGER32)/INTEGER32;
PROC GCD (A, B);
IF A = 0 THEN B => GCD; EXIT FI;
IF B = 0 THEN A => GCD; EXIT FI;
GCD (B, A - B) => GCD;
END ;
:: I/O FROM MUSS LIBRARY
OUT.I ( GCD ( IN.I(), IN.I() ), 0 ) ;
*END

In FLOCODER file format:

@TITLE GCD
@COL 1S-2R-3R-4T-6T-8R-9R-10R-11F
@COL 7
@COL 5
@ROW 4-5
@ROW 6-7
@FLOW 1-2-3-4FALSE-6FALSE-8-9-10-11
@FLOW 4TRUE-5-9
@FLOW 6TRUE-7-9
@BOX 1.0
Program to calculate 
Greatest Common Divisor
Using Euclidean Algorithm
@BOX 1.1
MODULE GCDEX
@BOX 2.0
Specify procedure with
two arguments returning an int
@BOX 2.1
PSPEC GCD(INTEGER32, INTEGER32)/INTEGER32;
@BOX 3.0
Procedure is GCD with args A & B
@BOX 3.1
PROC GCD (A, B);
@BOX 4.0
Test if A is zero
@BOX 4.1
IF A = 0 
@BOX 5.0
Return B
@BOX 5.1
B => GCD;
@BOX 6.0
Test if B is zero
@BOX 6.1
IF B = 0 
@BOX 7.0
Return A
@BOX 7.1
A => GCD;
@BOX 8.0
Recursively call GCD
with B and the difference of A and B
and return the result
@BOX 8.1
GCD (B, A - B) => GCD;
@BOX 9.0
End of GCD function
@BOX 9.1
END ;
@BOX 10.0
Main Body code:
Input two integers using MUSS Library
IN.I, invoke GCD. Print the result using
MUSS library OUT.I in minimum digits.
@BOX 10.1
OUT.I ( GCD ( IN.I(), IN.I() ), 0 ) ;
@BOX 11.0
All done
@BOX 11.1
*END

As Seen:

GCD in FLOCODER

† The MUSL code is handwritten, not the code that Flocoder would have generated; that was a bit uglier!

\$\endgroup\$
7
\$\begingroup\$

2005 - F#

F# (pronounced eff sharp) is a strongly typed, multi-paradigm programming language that encompasses functional, imperative, and object-oriented programming techniques. F# is most often used as a cross-platform CLI language, but can also be used to generate JavaScript and GPU code. Wikipedia

Task1

printfn "F# was made in 2005!"

Task2

let n = int32( System.Console.ReadLine() )
for y in 1..n do
    for x in 1..n do
        if x = 1 || x = y || x = n then
            printf "N"
        else
            printf " "
    printfn ""

Explanation:

x = 0 || x = y || x = n

takes care for printing only vertical ( left and right | ) and diagonal ( \ )

Task 3

simple implementation of Euclidean_algorithm

let a = int32( System.Console.ReadLine() )
let b = int32( System.Console.ReadLine() )

let gcd a b =
    let mutable _a = a
    let mutable _b = b
    while _b <> 0 do
        let c = _a % _b
        _a <- _b
        _b <- c
    _a

printfn "%d" ( gcd a b )

gcd can be also written using tail recursion. Thanks to VisualMelon

let rec gcd a b =
    if b = 0 then
        a
    else
        gcd b (a % b) 
\$\endgroup\$
6
  • \$\begingroup\$ The task does seem to be after a recurisve gcd (and mutability isn't very F#y), let rec gcd a b = if b = 0 then a else gcd b (a % b) fits the bill \$\endgroup\$ Apr 10, 2015 at 12:06
  • \$\begingroup\$ I prefer to use iterative solutions over recursive, due to stack overflow when deep recursions. but yes in this case it could be better. \$\endgroup\$
    – wasikuss
    Apr 10, 2015 at 12:37
  • 3
    \$\begingroup\$ However, the F# compiler is Tail Recursive, which means the recursive call to gcd doesn't create a deeper stack frame, because the state of the current frame doesn't need to be preserved (the value is returned straight to caller), so it will won't overflow the stack. \$\endgroup\$ Apr 10, 2015 at 12:43
  • \$\begingroup\$ @VisualMelon, I've never heard about Tail Recursion, good to know :) \$\endgroup\$
    – wasikuss
    Apr 10, 2015 at 13:04
  • \$\begingroup\$ Your Task2 solution appears to be off slightly, it is effectively running n+1 rather than n; you can fix this by replacing all the 0s with 1s. \$\endgroup\$ Apr 10, 2015 at 13:20
7
\$\begingroup\$

2004 - Axo

"Just another" Befunge-inspired language, but hey, it's from 2004, at least it's not a Brainfuck clone, and the interpreter is still available.

Task 1:

>0                          !
%"Axo was created in 2004!$"!
>[#!\
!( !

The other tasks also contain this output routine. An oddity about Axo is that it has a string mode (") and a raw mode ('). In string mode, $ pushes a newline instead of a literal $. The output routine is simply: [# "if top of stack is not zero" ( "output character".

Task 2:

>0" ?n">[#!!
       !( !}
%:0        !
%:+1;     ("$"<
>[;-#!\
     >0.>[,-#!^
             >;,-  #!'N'%
             %      !
             >,    #!'N'%
             %      !
             >[,-1-#!'N'%
                    >' '%
        ^.+1,(          <

This program uses the registers (; and ,) as X and Y counters. The value for n is kept on the stack. Apart from that it's just two nested loops, nothing fancy.

Task 3:

>0" ?a">[#!!
       !( !}
%:         !
>0" ?b">[#!!
       !( !}
%.         !
@
>,#!;{"$"(\
.  >;,!
!:,]&/!

The first bit of the program (before the @) just asks for two numbers and stores them in the two available registers. The last bit is Euclid's algorithm:

  • ,#: while , is nonzero:
  • ;,/&]: push ; mod ,
  • ,:: store the value of the , register in the ; register
  • .: store the remainder that was pushed earlier in the , register
  • {;: afterwards, output the contents of the ; register
\$\endgroup\$
7
\$\begingroup\$

1997 - ECMAScript

ECMAScript is the standard that arose from JavaScript.

JavaScript was announced to the world in December 1995 by Netscape, and supported in Netscape Navigator in March 1996. Microsoft made a similar language, JScript, which was included in Internet Explorer 3.0 in August 1996.

In November 1996, Netscape took the language to Ecma International, a non-profit standards organisation that worked on the specification. This was published as ECMA-262, which was first released in June 1997. The name is apparently a compromise between Netscape and Microsoft, whose arguments were a major part of drafting the first standard.

Eagle-eyed viewers will note that my solution is essentially JavaScript with a different title; JavaScript is supposed to be compliant with ECMAScript, and then add a few features of its own. As such, I was able to write this without having to look up any ECMAScript syntax.

ECMAScript fiddle to try my code.

Task 1

var challenge1 = function() {
  console.log("ECMAScript was made in 1997!");
};

Task 2

var challenge2 = function(N) {
  for (var row=1; row<=N; row++) {
    
    var row_str = "N";
    for (var col=2; col<N; col++) {
      if (col == row) {
        row_str += "N";
      } else {
        /* We have to use non-breaking spaces because repeated normal spaces 
           are compressed into a single space when printed. */
        row_str += "&nbsp;";
      }
    }
    row_str += "N";
    
    console.log(row_str);
  }
};

Task 3

var challenge3 = function(a, b) {
  while (b != 0) {
    var t = b;
    b = a % b;
    a = t;
  }
  return a;
}
\$\endgroup\$
7
\$\begingroup\$

2007 - GolfScript

GolfScript was one of the first languages created specifically for code golf.

Task 1

;"GolfScript was made in 2007!"

The ; drops any user input from the stack before pushing the output string. I'm not familiar enough with GolfScript practices to know if this is necessary or not.

Task 2

~:s{s{\.@.@=\.s=@+\.1=@+"N"" "if@@1-}s*;n\1-}s*;

Stores the size in s, then executes a nested loop via the {...}s* idiom. Most of the code in the inner loop is stack manipulation to generate the j==i || j==s || j==1 logic. Note the use of 1- instead of (, which was added to the language two weeks after the first version came out.

This could most likely be golfed further.

Task 3

~{.@\%.}do;

Just a rip-off of the solution from the GolfScript website.

\$\endgroup\$
2
  • \$\begingroup\$ Here’s task 2 in 44 bytes:Try it online! the ( can be 1- \$\endgroup\$
    – noodle man
    Oct 11, 2023 at 18:47
  • \$\begingroup\$ Although after writing this I realized that when all the parens are removed it’s the same length as yours… \$\endgroup\$
    – noodle man
    Oct 11, 2023 at 18:54
7
\$\begingroup\$

2003 - Groovy

Groovy is a dynamic programming language made for the Java platform. Its development was started by James Strachan in 2003.

Task 1 - Hello World

println "Grails was made in 2003!"

Test 2 - ASCII "N"

def i=5
def range=(1..i)
println (range.collect { r->
    range.collect{c->
        (r==c||c==range.min()||c==range.max())?'N':' '
    }.join()
}.join("\n"))

Test 3 - GCD

def GCD;
GCD = {a,b->b==0?a:GCD(b,a%b)}
println GCD(a,b)
\$\endgroup\$
7
\$\begingroup\$

1987 - Perl

Perl is a high-level scripting language developed by Larry Wall in 1987. He used it for processing his reports, which has lead to the backronym Practical Extraction and Reporting Language (but Perl is not, in fact, an acronym for anything).

It’s based on Unix shell programming, and you can see features of that in the language: for example, all variables have a sigil, and it has builtins that mimic common shell commands.

The original 1.0 source code was posted to a newsgroup in December 1987. The current stable version is Perl 5, which began life in 1993, and has had incremental new versions ever since. A specification for Perl 6 was started in 2000, but it does not have an official implementation, and it is sometimes said that Perl 6 is vapourware.

Perl is often derided for its heavy use of regular expressions.

I tested my code on Perl 5, but I believe this is all vanilla Perl and should work on any version.

Task 1

This could be done as a one-liner, but I thought it worth demonstrating sigils (the dollar signs) before variable names.

sub task1
{
  $language = "Perl";
  $year = "1987";
  print "$language was made in $year!\n";
}

Task 2

sub task2
{
  my $N = @_[0];
  for (my $row=1; $row <= $N; $row++) {
    for (my $col=1; $col <= $N; $col++) {
      if ($col == 1 or $col == $N or $col == $row) {
        print "N";
      } else {
        print " ";
      }
    }
    print "\n";
  }
}

Task 3

This is the subtraction version of Euclid’s algorithm.

sub task3
{
  my $a = @_[0];
  my $b = @_[1];

  while ($a != $b) {
    if ($a > $b) {
      $a -= $b;
    } else {
      $b -= $a;
    }
  }

  print "$a\n";
}
\$\endgroup\$
1
  • \$\begingroup\$ Perl 6 will never have a single official implementation, instead anything that passes the spec tests can be considered Perl 6. The first official release of the spec tests happened in December of 2015. Perl did not always have the my keyword, so your belief that this works on all versions is utterly false. I suppose I can forgive you for a bit of ignorance considering you wrote my $a=@_[0] instead of the more correct my $a=$_[0] or even better my ($a,$b)=@_; and that you used the error prone C-style for loop instead of for my $col (1..$N){…} \$\endgroup\$ Feb 4, 2016 at 22:51
7
\$\begingroup\$

1991 - Fortran 90

From Wikipedia:

The much delayed successor to FORTRAN 77, informally known as Fortran 90 (and prior to that, Fortran 8X), was finally released as ISO/IEC standard 1539:1991 in 1991 and an ANSI Standard in 1992. In addition to changing the official spelling from FORTRAN to Fortran, this major revision added many new features to reflect the significant changes in programming practice that had evolved since the 1978 standard

“Hello, World”

In particular, Fortran 90 adds free-form source input (yay!), which is nice even for Hello World.

program say_my_name
  print '(A)', "Fortran 90 was made in (you guessed it) 1991"
end program say_my_name

ASCII art “N”

In the ASCII art task, the handy I0 format specifier from Fortran 95 has to go. Too bad if you want to print N for N ≥ 10¹⁰

program paint_N
  integer            :: N, i
  character(len=500) :: fmt

  read*, N

  do i=1,N
     write(fmt, "('(', 2(A, ',', 'T', I11, ','), A, ')')") &
          "'N'", i, "'N'", N, "'N'"
     print fmt
  end do
end program paint_N

Greatest common divisor

To compute the GCD, we use Euclid's algorithm because Fortran 90 lacks the bitwise operations. (Even if ifort -e90 accepts them; gfortran has -std=f95 but no corresponding std=f90.)

program Euclidean_GCD_algorithm
  integer :: a, b

  do 
     read(*,*, END=1) a, b
     print*, gcd(a,b) 
  end do

1 continue

contains

  integer function gcd(a, b)
    integer, intent(in) :: a, b
    integer             :: v, t

    gcd = a 
    v   = b

    do while (v /= 0)
       t   = v
       v   = mod(gcd, v)
       gcd = t 
    end do
  end function gcd
end program Euclidean_GCD_algorithm
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Oh my - we're officially into languages that are older than me. \$\endgroup\$ Apr 16, 2015 at 5:56
  • \$\begingroup\$ Well, I won't be doing any Fortran versions that are older than me. No thanks :-) \$\endgroup\$
    – xebtl
    Apr 16, 2015 at 7:34
7
\$\begingroup\$

1973 - COMAL

Quite a number of COMAL resources can be found on the web. Since I have no prior exposure to COMAL (we are now well past my birth year), I'll quote and link some of them here.

COMAL (Common Algorithmic Language) is a computer programming language developed in Denmark by Benedict Løfstedt and Børge R. Christensen in 1973.

COMAL was created as a mixture of the prevalent educational programming languages of the time, BASIC, Pascal … The language was meant to introduce structured programming elements in an environment where BASIC would normally be used.

I used OpenComal, originally by Jos Visser and forked to run on recent Linux systems by Christian Pietsch, to write and test these programs. Jos defines COMAL as

A crossover between Basic and Pascal, with the best features of both and none of the drawbacks of either.

OpenComal comes with nice documentation, which is more than detailed enough to make it easy to write the code. It also gives some history:

In the early history of micro computing, resources … were scarce … BASIC was the language of choice back then. Almost all micro computers featured their own dialect of BASIC … Most of the time they lacked about everything necessary to develop well-structured and maintainable programs …

The principles of structured programming were available of course, but structured languages like PASCAL were not really available for small micro's due to limitations in the micro's resource capacity and the then available compiler technology.

Somewhere in Denmark a teacher named Borge Christensen understood the potential dangers of the BASIC habits and he [modified] an available BASIC interpreter so as to create a new language which should support structured programming concepts like PROCedures, FUNCtions and GOTO-less loops. The first Comal … interpreter was born.


Task 1

   10 PRINT "COMAL was made in 1973!"

Every line has to be numbered, but note that the line numbers are used only for editing — there is no GOTO. The COMAL executable is an editor and interpreter rolled into one. You enter the code; list prints it back to you nicely formatted (as the Compute! article linked above would have it: “You type in a BASIC program; when you list it back, it looks as if it has been changed to Pascal”). The line numbers allow you replace, edit, or delete certain lines. When you are satisfied, you run the program. Actually, this way of programming was quite fun — just remember to save often because the interpreter crashes sometimes.

Task 2

COMAL uses postfix sigils to distinguish variable types. Thus n# is an integer, n$ a string, and n a floating point variable. Booleans are of the 1/0 variety and indices (for substrings or arrays, though the latter can be changed with DIM) start at 1.

   10 INPUT "Enter a number ": n#
   20 
   30 n$:=" N"
   40 
   50 FOR i:=1 TO n# DO
   60   FOR j:=1 TO n# DO
   70     n:=1+(j=1 OR j=i OR j=n#)
   80     PRINT n$(n:n),
   90   ENDFOR j
  100   PRINT 
  110 ENDFOR i
  120 
  130 END

Task 3

Recursion is supported (the file TODO does state ”Heavily recursive Comal programs mess up the interpreter a bit”, but I had no problems with gcd). FUNCtion and PROCedure names have the same sigils as variables. A function or procedure may be declared CLOSED meaning that all variables are local (in this case, it does not change anything of course).

   10 INPUT "Enter two numbers ": a#, b#
   20 PRINT gcd#(a#, b#)
   30 
   40 FUNC gcd#(a#, b#) CLOSED
   50   IF b#=0 THEN RETURN a#
   60   RETURN gcd#(b#, a# MOD b#)
   70 ENDFUNC gcd#
\$\endgroup\$
4
  • \$\begingroup\$ Did you intend to leave the PRINT a," ",b? Seems like it was for debugging purposes. \$\endgroup\$ Apr 28, 2015 at 22:22
  • \$\begingroup\$ @kirbyfan64sos absolutely correct, thanks. \$\endgroup\$
    – xebtl
    Apr 29, 2015 at 8:25
  • \$\begingroup\$ Is using floating point deliberate in task 3? \$\endgroup\$
    – CJ Dennis
    May 2, 2015 at 15:54
  • \$\begingroup\$ @CJDennis Not really, except that they are easier to type and it does not matter for smaller inputs. But you are right that there is a range of larger numbers where integers work but floats don't (e.g. 971*983*991*997*967*937 = 854491261035335569 and one of its factors), so I changed the code to use integers. \$\endgroup\$
    – xebtl
    May 2, 2015 at 18:49
7
\$\begingroup\$

1985 - QuickBASIC

QuickBASIC is essentially the same thing as its later version QBasic, albeit with a few features that QBasic doesn't have (such as a compiler). It was part of a second generation of BASIC versions that moved more toward structured programming--eliminating the requirement for line numbers, tending toward using loops rather than gotos (though not exclusively), and allowing procedural abstraction via "subprograms."

(Wikipedia gave vague and possibly conflicting information on what control structures were available in the first version of QuickBASIC, and Google wasn't particularly helpful either; so if you see something that you know shouldn't be in here, let me know and I'll change it.)

Task 1

CLS
PRINT "QuickBASIC was made in 1985!"
END

In QBasic for DOS, at least, the CLS command is needed to clear the screen between successive invocations--otherwise, you'll just keep adding a new QuickBASIC was made in 1985! line each time you run the program.

Task 2

CLS
INPUT "Enter size of N: ", size
FOR i = 1 TO size
   FOR j = 1 TO size
      IF j = 1 OR j = i OR j = size THEN PRINT "N"; ELSE PRINT " ";
   NEXT j
   PRINT
NEXT i
END

The variables here don't have any type indicators and so are numeric by default. If you try to give the INPUT statement something non-numeric, it will print an error message and ask you again. Semicolon isn't a statement separator, it suppresses newline at the end of the PRINT statement.

Task 3

CLS
INPUT "Enter two integers: ", a, b
WHILE a > 0
  LET tmp = b
  LET b = a
  LET a = tmp MOD a
WEND
PRINT "GCD is"; b
END

The INPUT statement with multiple variables accepts two comma-separated numbers. The name of the WEND keyword probably derives from While-END, but the association with wend gives it a nice poetic touch.

\$\endgroup\$
6
\$\begingroup\$

2000 - ActionScript

ActionScript is a member of the ECMAScript family, developed for scripting the animation software Flash. By making Flash programmable, it allowed for interactive menus, games, etc.

Version 1.0 was released in September of 2000 as part of Flash 5. Although Flash 4 had a simple scripting language known as "Actions," ActionScript 1.0 added significant new features such as user-defined functions, so I claim 2000 as the year of origin for ActionScript. (Source: Wikipedia)

On a personal note: ActionScript was the second programming language I learned, after QBasic. I still remember with great fondness the fractal generators, cipher machines, and vegetable-shooting games I created with it. Going back to it for this post was fun.

Note: These examples are tested with ActionScript 2.0, which is the oldest version I have access to. I've never used ActionScript 1.0. But as far as I know, I haven't used any 2.0-specific language features here.

Task 1

The easy way would be to output the text to a debugging window via trace(). But this is an animation software--we can do better.

createTextField("field_txt", 0, 0, 0, 200, 50);
field_txt.text = "ActionScript was made in 2000!";

ActionScript "Hello World" variant

Task 2

The next two examples assume that text boxes with the appropriate names and properties have already been created. One can do this programmatically, as above, or by putting them on the stage with the GUI. The latter saves a lot of typing, of course.

input_txt.onChanged = function() {
    number = int(input_txt.text);
    output_txt.text = "";
    for(i = 0; i < number; i++) {
        for(j = 0; j < number; j++) {
            if(j == i || j == 0 || j == number - 1) {
                output_txt.text += "N";
            } else {
                output_txt.text += " ";
            }
        }
        output_txt.text += "\n";
    }
}

It's helpful to set output_txt to a monospace font.

ActionScript ASCII "N"

Task 3

a_txt.onChanged = b_txt.onChanged = function() {
    if(a_txt.text && b_txt.text) {
        a = int(a_txt.text);
        b = int(b_txt.text);
        while(a > 0) {
            tmp = b;
            b = a;
            a = tmp % a;
        }
        output_txt.text = "GCD is " + b;
    } else {
        output_txt.text = "";
    }
}

ActionScript GCD

Both examples 2 and 3 update the result live as you type in the input boxes.

\$\endgroup\$
6
\$\begingroup\$

2001 - Felix

Felix is a powerful, multi-paradigm programming language inspired by a mix of C++ and the ML langauges (heck, the creator was a member of the C++ commitee at one point). It's very powerful and pretty awesome, taking a very different approach to several concepts. It features a dynamic plugin system (YES!!!!), a C++ code generator (the standard library's string type is just a wrapper over the C++ std::string), and a nice syntax. It also takes a unique approach to things such as calls (like Nim, a.b == 'b a'), indexing (calling an integer with a sequence indexes it), a grammar defined in user-space (a.k.a. you can extend the grammar inside your Felix script), and lvalues/rvales (there are none!).

The only real issue is that lack of half-decent documentation, but there are plenty of examples (the driver, the web server, the utilities: all written in Felix) and a very helpful mailing list.

Also, when you read some of the mailing list posts describing how certain internals work, you seriously feel like you gained brain cells. ;)

Task 1

println "Felix was made in 2001!";

Task 2

proc ascii(n: int) = {
    for var i in 0 upto n - 1 do
        for var j in 0 upto n - 1 do
            print (if j == 0 or j == i or j == (n - 1) then "N" else " ");
        done
        println "";
    done
}

ascii $ stdin.readln.int; // or stdin.readln.int.ascii;

Task 3

fun gcd(a: int, b: int) => if b == 0 then a else jump gcd(b, a % b);
                                              // ^ jump is for tail recursion

match split_first(stdin.readln, " ") with
| Some (a, b) => println $ gcd(a.int, b.int);
| #None       => ;
endmatch;
\$\endgroup\$
6
\$\begingroup\$

1992 - Dylan

Dylan is a multi-paradigm programming language, that has support for both functional and object-oriented programming. It was originally written at Apple to be the programming language for the Newton, but that went wrong, and the Newton's software ended up written in a combination of C and a stripped-down version of Self named NewtonScript.

Despite its syntax, Dylan is a Lisp derivative. Some of the syntax does show it, however: variable names like this-one and *this*one* are considered valid, and thus operators need to be seperated from their arguments by spaces. Dylan also has Lisp-style macros that can actually extend the syntax to some extent. For example, the for construct as used in the ASCII art example is actually a macro, not a built-in.

Actually compiling a Dylan program is a bit of a hassle. You need to define at least a library, a module, and a library interchange file (LID), in three different files. Because both the library and the LID are basically only boilerplate for small programs like these, I have provided only the modules. OpenDylan, which I used, can generate all the necessary boilerplate for you using make-dylan-app <name>.

Task 1

Module: task1
format-out("Dylan was created in 1992!\n");

Task 2

Module: asciin

define function N (size :: <integer>)
  for (line from 1 to size)
    for (col from 1 to size)
      format-out(
        if (col = 1 | col = size | col = line)
          "N"
        else
          " "
        end if
      );
    end for;
    format-out("\n");
  end for;
end function N;

N(string-to-integer(application-arguments()[0]));

Task 3

Dylan has a built-in gcd function, so all you need to do is write an I/O wrapper:

Module: gcd
format-out("%d",apply(gcd,map(string-to-integer,application-arguments())));

However, if you want to write your own gcd, you can do it like this:

Module: customgcd
define function my-gcd (a :: <integer>, b :: <integer>)
   if (b = 0)
      a
   else
      my-gcd(b, modulo(a, b))
   end if
end function my-gcd;

format-out("%d\n",apply(my-gcd,map(string-to-integer,application-arguments())));

This also shows how it is a multi-paradigm language: N from task 2 is written in imperative style, my-gcd is written in functional style.

\$\endgroup\$
6
\$\begingroup\$

1986 - Oberon

Oberon is a language designed by Niklaus Wirth to increase the power of Modula-2 and decrease its complexity (to quote Wikipedia).

To me, it's just a slightly nicer version of Pascal, despite the ALL-CAPS KEYWORDS THAT MAKES IT LOOK LIKE YOUR PROGRAMS ARE SCREAMING IN PAIN. :)

Task 1

MODULE print;

IMPORT Out;

BEGIN
    Out.String("Oberon was made in 1987!"); Out.Ln;
END print.

Task 2

    MODULE ascii;

IMPORT Out, In;

PROCEDURE Ascii(n: INTEGER);
VAR i, j : INTEGER;
BEGIN
    i := 0; WHILE i < n DO
        j := 0; WHILE j < n DO
            IF (j = 0) OR (j = i) OR (j = n-1) THEN Out.String("N")
            ELSE Out.String(" ") END; INC(j)
        END; Out.Ln; INC(i)
    END
END Ascii;

VAR n : INTEGER;
BEGIN
    In.Int(n); Ascii(n)
END ascii.

Task 3

MODULE gcd;

IMPORT Out, In;

PROCEDURE Gcd(a, b : INTEGER): INTEGER;
BEGIN
    IF b = 0 THEN RETURN a
    ELSE RETURN Gcd(b, a MOD b) END;
END Gcd;

VAR a, b : INTEGER;
BEGIN
    In.Int(a); In.Int(b); Out.Int(Gcd(a, b), 0); Out.Ln
END gcd.
\$\endgroup\$
6
\$\begingroup\$

1978 - MATLAB

So Wikipedia was a bit ambiguous on the release date. But this was one of the options.

MATLAB is mathematical language based on numerical calculation. The newer versions do support symbolic calculation (via MuPAD) like Mathematica. The language is heavily matrix / vector based and most of the operators are defined for matrices with special cases for the element-wise use (* is matrix multiplication .* is element-wise multiplication).

With language as old as MATLAB, I can not make any guarantees on if the tasks would work for the first variants of the language.

Task 1

'MATLAB was made in 1978'

Notice how I do not use ";" at the end. That woud suppress the output. The default behaviour is to save the result of any assignment-less result (like this) to variable "ans". Because there is no semicolon after the statement the contents of the assignment variable (ans here) are printed out. You could use fprintf(format, ...) also.

Task 2

function [] = printn(n)
    ROW = blanks(n);
    for i=1:n
        for j=1:n
            if (j == 1) || (j == i) || (j == n)
                ROW(j) = 'N';
            else
                ROW(j) = ' ';
            end
        end
        fprintf('%s\n', ROW);
    end
end

I have my doubts if strings were a part of the first version of the language but this is quite vanilla solution never the less. The empty brackets [] mean the function does not return any values.

Task 3

function [value] = mygcd(a,b)
    if (a == b) || (b == 0)
        value = a;
    else
        A = max(a,b);
        B = min(a,b);
        while B  > 0
            a = B;
            B = mod(A,B);
            A = a;
        end
        value = A;
    end
end

Matlab does have gcd built-in so I used mygcd as the function name. I also assumed a and b are scalars. The stack-overflow also happened with the recursive version so I used iterative Euclid's algorithm. The function returns the value, so you'd need to print it yourself.

fprintf('gcd(%d, %d) = %d\n', 40, 15, mygcd(40, 15));
\$\endgroup\$
4
  • \$\begingroup\$ You need to change your answer some bit, Your title is not as OP want, You used ** instead of # Also First task show mathematica instead of matlab. \$\endgroup\$ Apr 20, 2015 at 10:13
  • \$\begingroup\$ @kuldeep.kamboj the first task does work in matlab also. The format is only a bit settings dependent. If you want to have settings independent format then you can use: fprintf('Matlab was made in 1978\n'); Like I wrote. \$\endgroup\$
    – Puzzled
    Apr 20, 2015 at 17:11
  • 1
    \$\begingroup\$ I don't know what was the functionality of first version of Matlab, but Task 2 is a serious overkill. The sequence t=eye(n); t(:,1)=t(:,end)=1; t*='N'; t(t==0)=' '; disp(char(t)); does the job perfectly. The syntax of the first Matlab might be a bit different, but it must have had some "matrix" operations. Yet replacing loops for matrix operations is so obvious in Matlab, there are even functions created to easily replace a bunch of vector operations into a single matrix one (vide repmat). \$\endgroup\$ Apr 20, 2015 at 23:23
  • \$\begingroup\$ Agreed on that fact. But given that the first version of matlab was that long ago, I'm quite sure the syntax was widely different back then (for example might not have had splicing ":" etc). For that reason I decided to use loops. (Otherwise I'd have to know the library reference for the first Matlab) \$\endgroup\$
    – Puzzled
    Apr 22, 2015 at 7:17
6
\$\begingroup\$

1982 - Maxima

Maxima is a free and open source computer algebra system based on a 1982 version of Macsyma. It is written in Common Lisp. As a programming language, it has a ALGOL-like syntax but a Lisp-like semantics.

Task 1

print("Maxima was made in 1982!")$

Task 2

asciiartn (n) :=
    printf (true, "~{~{~:[ ~;N~]~}~%~}",
        makelist (makelist (member (j, [1, i, n]), j, n), i, n))$

printf is a extremely powerful function. It provides the Common Lisp function format in Maxima.

Task 3

gcd1 (m, n) := if n = 0 then m else gcd1 (n, mod (m, n))$
\$\endgroup\$
6
\$\begingroup\$

1976 - SAS

Language History

SAS, previously an acronym for Statistical Analysis System, was developed at North Carolina State University from 1966 to 1976 by Anthony Barr, a professor at NC State, and James Goodnight, a student at NC State. The SAS Institute was incorporated in 1976, when it released the first commercial version of SAS, which was a redesign of the original version developed at NC State.

The language's syntax was based on PL/I, and indeed the internals were originally written in PL/I. However, the internals have since been rewritten in C.

Once the reigning king of commercial statistical software, in recent years interest in SAS has waned, giving way to languages like R and Python. The reasons for this are numerous, including the fact that a single user license for SAS can cost upward of $10,000 USD annually whereas R and Python are free, and SAS is strictly and vehemently closed source while R and Python are open source. However, though it's struggling to remain generally relevant, SAS still maintains a stranglehold on the world of FDA-regulated clinical trials.

"Hello, World!" Variant

%put SAS was made in 1976!;

The %put statement is actually a macro statement. It writes all text up to the semicolon to the log.

ASCII Art N

%let n = 7; /* Whatever N you want */

data _null_;
    /* Read the macro variable N */
    n = symgetn('n');

    if n = 1 then put 'N';
    else do;
        line = cat('N', repeat(' ', n-3), 'N');
        put line;

        do i = 2 to n-1;
            line = 'N';

            if i = 2 then call cats(line, 'N');
            else call catx(repeat(' ', i-3), line, 'N');

            if i = n-1 then call cats(line, 'N');
            else call catx(repeat(' ', n-i-2), line, 'N');

            put line;
        end;
    
        line = cat('N', repeat(' ', n-3), 'N');
        put line;
    end;
run;

This uses the cat() family of functions and call routines for string concatenation. However, string concatenation can alternatively be performed using ||.

GCD

%macro gcd(a, b);
    %local a_ b_ c;

    /* Store original inputs */
    %let a_ = &a;
    %let b_ = &b;

    %do %until(%eval(&b = 0));
        %let c = %sysfunc(mod(&a, &b));
        %let a = &b;
        %let b = &c;
    %end;

    %put The GCD of &a_ and &b_ is &a;
%mend gcd;

This defines a macro which call be called like %gcd(12, 15);. The result is written to the log.

\$\endgroup\$
5
\$\begingroup\$

1990 - zsh

The Z shell is a Unix shell in the family of sh, ksh, bash, etc. I'd never used it before today, but 1990 needed a language, and I knew a little Bash; this couldn't be too different, right?

Task 1

echo zsh was made in 1990!

No quotes necessary.

Task 2

for ((i = 0; i < $1; i++));
do
        for ((j = 0; j < $1 - 1; j++));
        do
                if (($i == $j || $j == 0));
                then
                        echo -n 'N';
                else
                        echo -n ' ';
                fi
        done
        echo 'N';
done

Invoke as zsh task2.zsh 7.

Note the C-inspired for loop syntax (though with semicolon and do/done); one quirk there is that the variable names don't use $ anywhere in the loop header. (Typically, shell variables stand without the $ only in assignments, like x=5.) The first command-line argument is available as $1. The double parens perform an arithmetic evaluation, which conveniently also supports comparison and boolean operators. Passing the -n option to echo suppresses the trailing newline; I decided to stop the inner loop short of the final column so I could use echo 'N' to print the last N and the newline at the same time.

Task 3

gcd() {
        if (($1));
        then
                gcd $(($2 % $1)) $1;
        else
                echo $2;
        fi
}

gcd $1 $2

Invoke as zsh task2.zsh 2706 410.

Here we get to define a function gcd. It is called just like a shell command, with space-separated arguments. Within the function, parameters are referenced with the same $1, $2, etc. as command-line arguments to a script. By using arithmetic evaluation in the condition, we can test if the argument is nonzero the same way as in C or Python.

The oddest thing (to me) is that you don't return the return value--you output it to STDOUT. (The return command sets the function's exit status, which is problematic if you're dealing with values outside the 0 to 255 range!) If you need to store the result instead of displaying it, just use retval=$(gcd $1 $2).

\$\endgroup\$
5
\$\begingroup\$

1977 - Icon

Icon language designed by Ralph Griswold in 1977. It is very much inspired from Algol Languages family specially Pascal language. It have some specialized feature like goal directed execution, generators and string scanning.

See Home Link

Task 1

procedure main()
    write("Icon was made in 1977");
end

Task 2

procedure main(args)
    i := 0
    n := args[1]
    repeat {
        j := 0
        repeat {
            v := n-1
            if j = 0 | j = v | i = j then
                writes("N")
            else
                writes(" ")
            j +:= 1;
            if j >= n then break
        }
        i +:= 1;
        write("")
        if i >= n then break
    }
end

Task 3

procedure main(args)
    a := args[1]
    b := args[2]
    while a ~= b do {
        if a > b then
            a -:= b
        else
            b -:= a
    }
    write(a)
end
\$\endgroup\$
4
\$\begingroup\$

1998 - PIKT

PIKT is a versatile system and network administration program. As such, it includes a scripting language. PIKT scripts are usually written to respond to certain events, but it is also possible to run PIKT scripts by themselves.

The syntax for stand-alone scripts and alert scripts are slightly different. The following programs are stand-alone scripts to be run from the command line. Input is taken via command line arguments.

The scripting language resembles a combination of awk and shell scripts, but is strongly typed. It has facilities for line-by-line (awk-style) processing of input data, and for inter-process communications. There's also a facility for accessing the previous run's variables. The tasks aren't very good to show this off, though.

Task 1:

begin output "PIKT was created in 1998!"

Task 2:

begin
      set #n = #value($ARGV[1])
      for #line=1 #line<=#n #line+=1
          set $s = ""
          for #column=1 #column<=#n #column+=1
             if #column==1 || #column==#n || #column==#line
                set $s .= "N"
             else
                set $s .= " "
             endif
          endfor
          output $s
      endfor

The following modification to this script makes it print an N the size of the previous input. This ability might seem useless, but if you're running cron scripts it is not. %n refers to the value #n had the previous time the script was run.

begin
      set #n = #value($ARGV[1])
      for #line=1 #line<=%n #line+=1
          set $s = ""
          for #column=1 #column<=%n #column+=1
             if #column==1 || #column==%n || #column==#line
                set $s .= "N"
             else
                set $s .= " "
             endif
          endfor
          output $s
      endfor

Task 3:

begin
      set #a = #value($ARGV[1])
      set #b = #value($ARGV[2])
      while #b != 0
          set #c = #a % #b
          set #a = #b
          set #b = #c
      endwhile
      output $text(#a)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.