Sunday, April 27, 2025

Works on my computer: If I gave you a program, could you run it on your computer?

Let's put one thing out of the way, any programming language, framework, environment can have excellent documentation that instructs how to build and run a particular program / project.  Github is full of examples.  More likely than not, when you go to a repository, whether it's code written in Python, C, JavaScript, Ruby, Java, Go, and so on., there will be documentation on how to download and run the build product, but more importantly, instructions on how to build the software from source (hint: look for the CONTRIBUTING file)

Having said that, in practice, on the streets, in the class rooms, in the cubicles, what happens is that folks aren't usually thinking how to get their program to work in your environment.  It works on their machine.

The following is my ranking for how easy is it to get someone's program to work on your computer.

For this exercise, I will assume that the receiver of the program has intermediate knowledge on how to run the code.   This list is not comprehensive because it's only from my personal experience, for that reason, I'll be reaching out to friends and family to give me additional suggestions.  I will try to make the criteria as objective as possible, and most likely refine it to be so as this evolves.

This is not only about programming languages, but also the various environments and systems they ran on.

The following is list is from Best to Worst.

1.

Microcomputers
I rarely have as positive experience with anything these days that can even remotely compare to the microcomputers in the old days.  If I gave you a tape or floppy disk that was for the Atari, or Apple ][, or if I asked you type in source-code directly from a magazine article, it worked.  There was no build instructions, other than "type Run and hit Enter".  The BASICA / GW-Basic era of the IBM-PC and clones would be in the same boat.  And so would QBasic.

2.

Turbo Pascal, Turbo C
If the IDE ran on your computer, whatever code you gave it would work.

3.

Visual C++
The reason this isn't in the same list as Turbo C is because it came a bit later, and as time progressed, it was more and more likely for projects to rely on third-party libraries.  Sure, it's possible that the Turbo C project you gave me requires some library that you have on your computer, but you forgot to give me, but it was much less likely.  Turbo C came with common extensions already included, such as graphics via BGI.  Visual C++ was a bit more modern, and pretty soon started to rely on third party libraries, but not as much in the beginning.

4.

Visual Basic
VB came with a ton of components built-right in, and in the beginning you could do a lot with what's in the box.  But because of it's popular extension capability with VBXs, within a few years it was less common to get a self-contained project.   In fact, it was a bit worse than Visual C++ in that, with C++, it was more likely that the third-party static .lib would be included in the source code that's delivered simply because of where the files are typically located on your own system.  Whereas, VBX files had no business residing along with the VB source.  You were supposed to put those in the C:\Windows\System folder.  I almost want to split VB between early-years and latter years.

5.

NodeJS
If you give me a NodeJS project, I know I can just do "npm install" to get all the dependencies.  But, what I need to do next to "run" it may require me to look at the docs, or check the scripts section in package.json.  Still, it's unlikely that I won't be able to run it, even if all you thought about was getting it to work on your computer and supplied no instructions.  Chances are, you would have added a command in the scripts section for yourself.
I would add Clojure to this list (leiningen).  Maybe Ruby, too.   And Rust.  Actually, I'm not that familiar with these tools.  If you are, and you think they're at least as good as NodeJS, let me know.

6.

C# with Nuget
This is almost tied with 5 because usually all I have to do is open it in Visual Studio and build and run it.   Wait, or do I type 'dotnet run'.   Is that enough?  Or do I have to type 'dotnet restore' first?  What if I use Visual Studio Code?  Do I just run it? Build it?
And that's the problem.  It has changed over time.  There used to be nuge.exe, then we're told not to use that, as msbuild has it built-in.  I think still does, but then there's the dotnet command-line tool, etc.
I don't think a few years goes by without Microsoft changing how package management works.  They keep trying to solve a problem wasn't broken to begin with, whereas NodeJS is still "npm install".
If you're reading this more than a few weeks after I wrote this blog, please check against -- Microsoft may have changed the rules again.
Yes, if you're in the cross-platform command-line "dotnet run" world, I'd say your experience is as good as it is with node.  The issue that Node has as far as "how do I run this", is superficially mitigated by dotnet's run command, except you have to know which project to run.  Often, when I "get" a C# codebase, it will contain lots of projects.  It's not immediately clear which one you "dotnet run" to start the main application.  Hoping there's an .sln file which the primary project set as default so you just hit F5, like it was VB in 1991.

7.

Modern C/C++
Yes, I know this seems too high on the list.  But honestly, there seems to be two types of C++ code that is shared:
1) A snippet of code, 5 to 25 lines, that is written in such a way that will work with your latest compiler without any problem -- this assume you know how to compile and run a stand-alone C/C++ file.
2) An entire project, and is so complex that the developer themselves have to use a full make system that you will be able to leverage, cmake/meson, vcpkg/conan, ninja, msbuild, etc.   You will likely be able to build it all and run.

8.

Python / PowerShell.
These are my least favorites because often enough Python .py / ipynb, or Powershell .ps1 files are just floating around stand-alone, expecting to be run.   A lot of non-programmers user these tools, and to them if it works on their computer, that's enough.  So when they give you their code, their optimism is that it will work on your computer, too.  Why not?
Well, I'll tell you why not.  You pip installed a Python package, or Install-Module a PowerShell module 9 months ago, and you're happily using it in your code.  Both of these tools come with some functionality built in (batteries included) that it's hard to keep track whether some module you've imported into your script is built-in to the environment, or is third-party?
And if yourself are not intimately familiar with what are built-in, you have to go through a trial and error phase where you run the code, wait for Python to tell you it doesn't understand an import. The you attempt to pip install it.  If that doesn't work, you have to google to see what's up.  If that doesn't help, you may have to contact your friend and ask, "Hey, what is this xyzzy thing you're importing?", just to them respond with, "oh, that's one of my files.  I'll e-mail it to you"  (facepalm)
What they're supposed to do is create a requirements.txt file, possibly with "pip freeze > requirements.txt", but that's going to output everything you've ever installed, so you have to use a virtual environment, etc., and most folks aren't going to do that 'cause they're just only thinking about what works on their computer.
It's a mess.
PowerShell is only slightly better, but actually it only teases you.  You *could* add the "Install-Module" commands right at the top of the .ps1 file so that when I run the .ps1, it'll install what's needed.  The problem is, the line will fail if the module is already there.  So what most people do is do a -force, which means you're redownloading and installing it every time, which is awful, but not as awful as the script not working.


Wednesday, June 1, 2022

Running a C# WebAssembly module outside of the browser

Based on "Future Possibilities for .NET Core and WASI (WebAssembly on the Server) | OD108", published May 27, 2022 by Steve Sanderson (SteveSandersonMS on Github, @stevensanderson on Twitter).  Video at https://youtu.be/A0vz_BWxIMc.

Prerequisites

.NET Version

.NET 7 or later is required.  I used ".NET 7 Preview 4", downloaded from: https://dotnet.microsoft.com/en-us/download/dotnet/7.0.

On Windows
I did not use the Installer.  Rather, I downloaded the "Binaries" and unzipped them to a local folder.  Then I added the root of that local folder to the front of the PATH environment variable, in a command prompt.
I also used the "Developer Command Prompt for VS 2022" command prompt.

On Mac
I installed .NET 7 Preview 4 using the installer.

WASI Runtime

To run the final .wasm file, I used wasmtime which I installed from here: https://wasmtime.dev/
I also ran it under wasmer, Installed from here: https://wasmer.io/

Build and Run

From a terminal or command prompt, create a new dotnet console project and "cd" into it:
dotnet new console -o HelloWasi 
cd HelloWasi

Then run it to make sure it works:
dotnet run 

It will just say "Hello world" or something like that.   Update Program.cs to output something more interesting.  Replace Program.cs with this code:

using System.Runtime.InteropServices;

System.Console.WriteLine($"Hello world! The time is {DateTime.UtcNow.ToLongTimeString()}");
System.Console.WriteLine($"OSArchitecture: {RuntimeInformation.OSArchitecture}");
System.Console.WriteLine($"OSDescription: {RuntimeInformation.OSDescription}");
System.Console.WriteLine($"FrameworkDescription {RuntimeInformation.FrameworkDescription}");
System.Console.WriteLine($"ProcessArchitecture {RuntimeInformation.ProcessArchitecture}");
System.Console.WriteLine($"RuntimeIdentifier {RuntimeInformation.RuntimeIdentifier}");

Build and run again:
dotnet build
dotnet run 

You should see output something like this.  Note what it says for "OSArchitecture"
Hello world! The time is 1:34:03 AM
OSArchitecture: X64
OSDescription: Microsoft Windows 10.0.19044
FrameworkDescription .NET 7.0.0-preview.4.22229.4
ProcessArchitecture X64
RuntimeIdentifier win10-x64

On macOS you'd get something like this:
Hello world! The time is 2:51:07 PM
OSArchitecture: X64
OSDescription: Darwin 19.6.0 Darwin Kernel Version 19.6.0: Tue Feb 15 21:39:11 PST 2022; root:xnu-6153.141.59~1/RELEASE_X86_64
FrameworkDescription .NET 7.0.0-preview.4.22229.4
ProcessArchitecture X64
RuntimeIdentifier osx.10.15-x64

Now let's update the project to target WebAssembly instead.
Add the Wasi.Sdk package:
dotnet add package Wasi.Sdk --prerelease

Or update the .csproj file to include this:
  <ItemGroup>
    <PackageReference Include="Wasi.Sdk" Version="0.1.1" />
  </ItemGroup>

Now when you do:
dotnet build

it will create HelloWasi.wasm next to the HelloWasi..exe file: 
bin\Debug\net7.0\HelloWasi.wasm
I'll be a single 16 MB file, because it contains all of the required .NET code.

Using Wasmtime, we can run this .wasm file:
wasmtime bin\Debug\net7.0\HelloWasi.wasm

Note the "OSArchitecture" field in the output:

Hello world! The time is 01:33:31
OSArchitecture: Wasm
OSDescription: Browser
FrameworkDescription .NET 7.0.0-dev
ProcessArchitecture Wasm
RuntimeIdentifier browser-wasm

Same exact .wasm file can run on any platform that supports WASI.  I tried it under wsl2 using wasmtime.  Also works under MacOS

Also tried the wasmer runtime. 


Tuesday, June 16, 2015

How to launch an elevated prompt

Here's a trick to launch an elevated prompt or run any app as Administrator elevated even from a non-elevated command prompt.

Use 'pseudo'.   It's kinda like 'sudo'

See https://github.com/kasajian/pseudo

Friday, May 1, 2015

Alternative to mocking static methods in C#

Curious what you guys think of this as an alternative to mocking static methods in C#?
Here's a a simply way to mock static methods without a mocking framework.

Say you have code like this:
        class Math
        {
            public static int Add(int x, int y)
            {
                return x + y;
            }

You want to "mock" the Add method, but you can't. Change the above code to this:

        class Math
        {
            public static Func Add = (x, y) =>
            {
                return x + y;
            };

Existing client code doesn't have to change (maybe recompile), but source stays the same.

Now, from the unit-test, to change the behavior of the method, just reassign an in-line function to it:
    [TestMethod]
    public static void MyTest()
    {
        Math.Add = (x, y) =>
        {
            return 11;
        };dada

Put whatever logic you want in the method, or just return some hard-coded value, depending on what you're trying to do.

This may not necessarily be something you can do each time, but in practice, I found this technique works just fine.

Another thing to keep in mind.   When you set the static variable like that, you should undo it when the test is complete.   One way to do that is to re-run the class's static initializer. 

 Example:
    typeof(SomeClassName).TypeInitializer.Invoke(null, null);

Wednesday, March 18, 2015

Favorite Day-of-Week calculation

/* 0 = Sunday, 1 <= m <= 12, y > 1752 or so */
int dayofweek(int y, int m, int d)
{
    static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    y -= m < 3;
    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}

Wednesday, January 28, 2015

A slight-of hand with .NET Lazy

The following is an example of a better way to read a value from a C# dictionary.

In C#/.NET, you will get an exception if you specify an non-existent key when attempting to read a value from a Dictionary.   The workaround is to call the TryGetValue method, which is awkward because of the out parameter, and the requirement of the additional variable declaration (< C#6).

Sometimes the behavior that you want is to get a null or 0 value when using an invalid key.   Other times you want to simply test the returned value to see if actually has a value, similar to Option/Maybe idiom in other languages.

Because of the extensible nature of C#, you can kinda have your cake an eat it to.   There's multiple ways to solve this problem, and some cool functional libraries have this built in (such as https://github.com/louthy/language-ext ), but with some slight-of hand, you can actually re-purpose the .NET built-in Lazy class to do this for you.

A Lazy object is an object that holds another object (or value), but it may be empty.  The reason it exists is for "memoization", in that, the Lazy object starts out empty, and then later, it may be filled with a value.

But no is stopping you from using Lazy as a way to indicate an optional value.   The following is an extension to IDictionary called GetValue.  When called with an existing key, it returns a Lazy object containing the value.   If the key does not exist, it returns an empty Lazy object.   You just have to call IsValueCreated on the Lazy object to determine if the value exists.   Alternatively, you can just use the .Value property and use the type's default value, such as 0 or null, when the key doesn't exist.  Depending on what you're doing, that may be what you want.

Either way, you don't have to use TryGetValue

References:

http://programmers.stackexchange.com/questions/159096/return-magic-value-throw-exception-or-return-false-on-failure/264516#264516

http://www.extensionmethod.net/csharp/idictionary/idictionary-getvalue

Wednesday, January 21, 2015

C# Dictionary to XML

Do you have a string dictionary in .NET code (C#) that want to write out to disk in nicely formatted XML?

A single line of text will do this:

new XElement("root", d.Select(
    kv => new XElement(kv.Key, kv.Value)))
        .Save(filename, SaveOptions.OmitDuplicateNam
espaces);


To read the XML file back later into a dictionary, is another single line:

var d = XElement.Parse(File.ReadAllText(filename))
    .Elements()
    .ToDictionary(k =>
        k.Name.ToString(),
        v => v.Value.ToString
());

That's it!

Monday, January 19, 2015

Easily Zip just the source of a Visual Studio project

When playing around, creating new Visual Studio projects such as a weekend project, you want an easy way to zip up my source and not worry about .pdb, obj/bin files, etc. files.
The .gitignore file is created when you create a Visual Studio project with the "Create new Git repository" selected.
You don't need to use pkzip because Git has the archiving feature built-in.  Just type:
git archive -o all.zip HEAD
and it will create all.zip of the latest source, without any of the stuff you don’t want in the .zip file like bin, obj, exes, nuget assemblies, etc.

Sunday, January 18, 2015

Double click file to run a PowerShell script

Typically, you cannot double click on a PowerShell script (.ps1 file) and have it automatically run, like you could with a batch file (.bat or .cmd). This is a good thing because someone may accidentally run something that was not meant to be run.

But what if you need to have someone run a PowerShell script and you just want them to double click a shortcut of some sort to make it happen.

The trick is to create a batch file that invokes the PowerShell. If you give the batch file and PowerShell script the same base name, then the batch file content doesn't have to change:


@echo off
pushd "%~d0"
pushd "%~dp0"
powershell.exe -sta -c "& {.\%~n0.ps1 %*}"
popd
popd

So, for instance, if you wish to run a PowerShell script called xyz.ps1, just create xyz.bat with the above content.

That's it!


By the way, the two pushd/popds are necessary in case the user's CDs is on a different drive. Without the outer set, the CD on the drive with the script will get lost.


Friday, November 21, 2014

How do I specify Git Commit id (hash) when launching a build with TFSBuild.exe?

TFSBuild.exe is the method by which you launch TFS build from the command line. TFSBuild.exe doesn't indicate how to specify a Git commit Id (the hash of the commit).
TFSBuild.exe discusses the /getOption:Custom option which, when used, lets use specify the change-set or label to base the build on, by specifying the change-set or label identifier with the /customGetVersion option. For a label, you start with an "L". For a change-set, you start with a "C".
You specify the git commit-id using the "Label" syntax, but add a "G:ref:" before the commit ID. As in: /customGetVersion:LG:ref:
Full syntax:
TFSBuild start teamProjectCollectionUrl teamProject definitionName /queue /getOption:Custom /customGetVersion:LG:ref:
Example usage:
TFSBuild start http://gitsourceserver:8080/tfs/MyCompany MyTeamProject MyBuildDefinition /queue /getOption:Custom /customGetVersion:LG:ref:0c9cc3ce

Saturday, November 15, 2014

Closures in C#, just like in JavaScript

How would I rewrite this JavaScript routine in C# using closure?

function makeConverter(toUnit, factor, offset) {
    offset = offset || 0;

    var converter = function (input) {
        return ((offset + input) * factor).toFixed(2) + " " + toUnit;
    };

    return converter;
}

var milesToKm = makeConverter('km', 1.60936);
var poundsToKg = makeConverter('kg', 0.45460);
var farenheitToCelsius = makeConverter('degrees C', 0.5556, -32);

log(milesToKm(10));
log(poundsToKg(2.5));
log(farenheitToCelsius(98));

You can do the same thing in C#:
public static Func<double, string> makeConverter(string toUnit, double factor, double offset = 0.0)
{
    return (input) => string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit);
}

public static void Main()
{
    var milesToKm = makeConverter("km", 1.60936);
    var poundsToKg = makeConverter("kg", 0.45460);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10));
    Console.WriteLine("{0}", poundsToKg(2.5));
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
You can further reduce it down to a single method:
public static void Main()
{
    Func<string, double, double, Func<double, string>> makeConverter =
        (toUnit, factor, offset) => (input) => string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit);

    var milesToKm = makeConverter("km", 1.60936, 0.0);
    var poundsToKg = makeConverter("kg", 0.45460, 0.0);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10));
    Console.WriteLine("{0}", poundsToKg(2.5));
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
You can even use old-style can use C# 2 syntax (yes, C# has had closure since 2005)
public delegate string del_t(double input);

public static del_t makeConverter(string toUnit, double factor, double offset = 0.0)
{
    return delegate(double input) 
    {
        return string.Format("{0:0.##} {1}", (offset + input) * factor, toUnit );
    };
}

public static void Main()
{
    var milesToKm = makeConverter("km", 1.60936);
    var poundsToKg = makeConverter("kg", 0.45460);
    var farenheitToCelsius = makeConverter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm(10) );
    Console.WriteLine("{0}", poundsToKg(2.5) );
    Console.WriteLine("{0}", farenheitToCelsius(98));
}
For comparison, if you didn't use closure, the traditional class-based way of solving this problem in C# would be:
public static void Main()
{
    var milesToKm = new Converter("km", 1.60936);
    var poundsToKg = new Converter("kg", 0.45460);
    var farenheitToCelsius = new Converter("degrees C", 0.5556, -32);

    Console.WriteLine("{0}", milesToKm.Convert(10) );
    Console.WriteLine("{0}", poundsToKg.Convert(2.5) );
    Console.WriteLine("{0}", farenheitToCelsius.Convert(98) );
}

class Converter
{
    string m_toUnit;
    double m_factor;
    double m_offset;

    public Converter(string toUnit, double factor, double offset = 0)
    {
        m_toUnit = toUnit;
        m_factor = factor;
        m_offset = offset;
    }

    public string Convert(double input)
    {
        return string.Format("{0:0.##} {1}", (m_offset + input) * m_factor, m_toUnit );
    }
}