Wednesday, November 16, 2022

Hacking Fake.Build for net7.0

It's too early yet to do the AltCover after-action for net7.0 like I did for net5.0; but it is proving a slog like net5.0 rather than being too transparent to mention like net6.0 was.

While the dotnet 7.0.100 build has its own problems, the Fake build system currently (5.23.x, 6.0 alpha) doesn't handle it at all - the former may work for limited scenarios, but more complicated ones fall over with library version mismatches; the latter politely askes for a v6 runtime and stops.

So, you have a build process based on a Fake script, but want to run with v7.0.100 as SDK, through your project global.json. What do?

Well, the Fake documentation gives some alternatives - turn the script into a net7.0 project that links against the Fake libraries; but that imposes some restrictions on how you set up targets, because you can only define such things (as opposed to the functions that define the target's intended action) after setting up a build context. Or you can run as a fsi script, but the documentation then leads into how to hack paket into the mix.

However, since net5.0, scripts are able to reference nuget packages directly, so rather than having a paket.dependencies, with a #r "paket: groupref [whatever] //", and a call out to paket on the command line, your scripts can be self-contained, with a block of #r "nuget: [library][, optional version]" lines at the top, and a command line that is just dotnet fsi [my fake script.fsx]

And doing it this way, you can build on the net7.0 runtime.

Friday, October 07, 2022

F# and OpenSilver v1.1

An update to the previous series of posts following the v1.1 stable release of OpenSilver.

The recipe given as before just works, when all packages are updated and the browser project build is done with net6.0. One warning is emitted using the latest (6.0.401) SDK, about the IntermediateOutputPath override. The fix is to create a Directory.Build.props in the browser project directory, and move the two lines added to the project previously to the new file

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <IntermediateOutputPath>shorter file path here</IntermediateOutputPath>
    <BaseIntermediateOutputPath>$(IntermediateOutputPath)</BaseIntermediateOutputPath>
  </PropertyGroup>
</Project>

While the System.Windows.Application.LoadComponent API now exists, it requires build-time XAML compilation, and that the named class which it decorates exists in the same assembly, so at this time would only make an adjustment to the C# assembly, replacing the constructor InitializeComponent call with one to LoadComponent, but leaving the same inheritance in the F# layer.

It is possible that the 2.0 release will allow XAML compilation in the F# layer, but on-the-fly compilation seems not to be on the cards.

Also, in language independent mode, the ImageBrush and ImageSource APIs used by the original Silverlight AstroClock are now present. Alas, while that means uncommenting that XAML clause can be done without compile or runtime error, the interesting bits are marked NotImplemented, and live in a "work in progress" source folder, so there is currently no point in doing so.

The resulting code for running with v1.1 can be found here.

Sunday, October 02, 2022

Q3 Cycling

Hot and parched for the first two months, then cooler and damper. This meant a fair bit of riding when it was comfortable to do so, and a collapse in September.

Fen Road, Fenstanton

July was mostly business rides or enjoying the sunshine locally, with one long ride up to St. Ives at the start of the really hot spell mid-month. Notably, the month ended with the arrival of the "Our Place in Space" exhibition, which straggled from Midsummer Common, all the way to Waterbeach, with a return ride that time down Mere Way.

Inner System

Totals at the end of the month 1213.7 on the old bike (+48.8), 1438.7 on the new (+515.3), for a total of 564.1 miles for the month, 2803 YTD.

Ely in the distance

Early in the month, I did a ride through Aldreth, north through Witcham to Coveney, before returning, adding the northernmost point of the limits map. This was in the driest part of the summer, and there were signs of wildfires on Grunty Fen that looked like stubble burning had made a comeback. The dry weather also gave chance to see what Cow Lane was like in the dry (and how not-green Horse River Green had become).

I did the space ride a couple more times, to get pictures when there were fewer other folk around, exploring also the adequate (for during the day) cyclepath along the A10 from Waterbeach to Milton, and then towards the end of the month, riding up to St Ives again, up to Houghton and Wyton, before riding the St Ives perimeter road, gaining another bit of limits; then passing a major crash on the A14 and getting my photos onto the BBC news website..

Houghton Mill

Totals at the end of the month 1264.9 on the old bike (+51.2), 1913.1 on the new (+474.4), and 159.76 for the folder (+38.8) for a total of 564.4 miles for the month, 3368 YTD.

Rivey Hill West - the dry way up

Before the weather completely broke, I made another Linton to Gt Chesterford run, finding a third bridleway, and the dry way up Rivey Hill; but after a ride to explore some new trails and find lunch on my birthday, the weather broke -- some rain, but mostly cooler, so most of the rides for the rest of the month were pure A-to-B, including going to hear the city's proclamation of the new King.

Proclamation

The only long ride was the Camcycle/CTC byways and highways ride around Cambridge at the end of the month, and that mostly by virtue of having to get to and from the start in addition to the circuit (which was around the length of a pretty-way each way circuit-commute to the Science Park, if not quite the same track).

Totals at the end of the month 1541 on the old bike (+276.1), 2045.7 on the new (+132.6) for a total of 408.7 miles for the month, 3777 YTD, having passed last year's whole-year total during the group ride.


Friday, July 01, 2022

Q2 Cycling

Dry, mild to warm weather, was the overall tone of the quarter, meaning that the ground was dry enough for off-road riding; and a lot of riding did get done.

St Helen's, Colne

Good Friday, an unscripted ramble up and around the busway took me north of St. Ives, and allowed me to add a little nubbin to the east of Earith to the "Outer Limits" map (mid-green), and from there things snowballed. The Easter weekend also saw a ride along the bridleway from Little Cow Lane through Linton, following parts of the Ickneild Way -- a much drier route than the previous, until Linton, and there finding that the bridleway had a river running down the middle. And from there, the next few rides kept up the theme, following the Ickneild Way west from Gt. Chesterford, and a bit further north from Linton. The month closed with a different big ride, up byways from Rampton to Aldreth.

Totals at the end of the month 947.8 on the old bike (+336.7), 250.2 on the new (+203.1), for a total of 539.8 miles for the month, 1141 YTD.

Avenue nr Little Bradley

May Day holiday, I took more of the Ickneild Way, north from Six Mile Bottom towards Newmarket (north from Burrough Green on the Outer Limits) and back to explore the byways that linked up to the Wilbrahams; and then having pushed the limits a bit, the next week I did the section south from Burrough Green to the Thurlows, with some exploration of byways near Carlton on the return. The following week, more Ickneild Way, from Melbourne to Letchworth, and another new section of limits. Finally, rounding the month off, I took my first cycling holiday since late '17, the CycleBreaks Gardens and Gallopers tour; marred slightly by pouring rain on the first day, it was a nice mix of new, familiar and "I've only cycled this in the opposite direction before".

Totals at the end of the month 1164.9 on the old bike (+217.1), 480.9 on the new (+230.7) + 14.1 off meter, and 151 on the tour bike, for a total of 612.9 miles for the month, 1754 YTD.

Bridleway

June opened with a ride out to Burwell, the byway-defined salient on the limits map, followed by another limits buster, going down from Wendens Ambo and Newport, south of Saffron Walden to Radwinter, then taking the Little Cow Lane path back, reaching the 2000 mile mark on 15-Jun vs 21-Aug-21, then finally a reprise of the Aldreth run, this time taking the byway looping north of Haddenham to Wilburton.

Totals at the end of the month 1164.9 on the old bike (+0), 923.4 on the new (+442.5) and 120.96 (+42.5) for the folder, for a total of 485.0 miles for the month, 2239 YTD - a number which I have considered a reasonable whole-year total in the past!

Stuck in a rut


Friday, May 13, 2022

F# under the covers XIX -- `with` clauses

Once again, the half-year update has included some interesting changes in code generation, this time around try/with clauses.

Two cases to show this, one simple, one more complex. As always, decompilations are for debug (unoptimized) builds, though in this case, the release builds differ only in details of the branch instructions.

      try
        ...
      with
      | :? FormatException -> Default
      try
        ...
      with
      | :? ArgumentException as a -> a |> (logException store)
      | :? NotSupportedException as n -> n |> (logException store)
      | :? IOException as i -> i |> (logException store)
      | :? System.Security.SecurityException as s -> s |> (logException store)
      | :? UnauthorizedAccessException as u -> u |> (logException store)

Before the 6.0.300 SDK update, the simple case was entirely direct in its handling of the exception

	.try
	{
	...
		IL_006d: leave.s IL_0098
	} // end .try
	catch [netstandard]System.Object
	{
		IL_006f: castclass [netstandard]System.Exception
		IL_0074: stloc.s 8
		IL_0076: ldloc.s 8
		IL_0078: isinst [netstandard]System.FormatException

but afterwards it becomes much fancier, with duplication of effort in the handled case, and only makes sense if the exit from the filter in the unhandled case is faster than from a catch.

	.try
	{
        ...
		IL_006e: leave.s IL_00b5
	} // end .try
	filter
	{
		IL_0070: castclass [netstandard]System.Exception
		IL_0075: stloc.s 8
		IL_0077: ldloc.s 8
		IL_0079: isinst [netstandard]System.FormatException
		IL_007e: stloc.s 9
                ...
	} // end filter
	catch
	{
		IL_008c: castclass [netstandard]System.Exception
		IL_0091: stloc.s 10
		IL_0093: ldloc.s 10
		IL_0095: isinst [netstandard]System.FormatException
		IL_009a: stloc.s 11
                ...
	} // end handler

the new code being equivalent to C# catch (object obj2) when ((((Exception)obj2) is FormatException) ? true : false)

The more complex case was like

	catch [netstandard]System.Object
	{
		IL_0010: castclass [netstandard]System.Exception
		IL_0015: stloc.1
		// ArgumentException ex2 = ex as ArgumentException;
		IL_0016: ldloc.1
		IL_0017: isinst [netstandard]System.ArgumentException
		IL_001c: stloc.2
		// if (ex2 == null)
		IL_001d: ldloc.2
		IL_001e: brfalse.s IL_0022
        ...

or, decompiled

	catch (object obj)
	{
		Exception ex = (Exception)obj;
		ArgumentException ex2 = ex as ArgumentException;
		if (ex2 == null)
		{
			NotSupportedException ex3 = ex as NotSupportedException;
			if (ex3 == null)
			{
			// ... throw on exhaustion
			}
			NotSupportedException j = ex3;
			Exception e4 = j;
			logException(store, e4);
			return result;
		}
		ArgumentException a = ex2;
		Exception e5 = a;
		logException(store, e5);
		return result;
	}

but now it looks like

	catch [netstandard]System.Object
	{
		IL_0010: castclass [netstandard]System.Exception
		IL_0015: stloc.1
		// object obj2 = ex;
		IL_0016: ldloc.1
		IL_0017: stloc.2
		// if (!(obj2 is ArgumentException))
		IL_0018: ldloc.2
		IL_0019: isinst [netstandard]System.ArgumentException
		IL_001e: ldnull // omitted in release
		IL_001f: cgt.un // omitted in release
		IL_0021: brtrue.s IL_0065
...
		IL_0065: ldloc.1
		IL_0066: unbox.any [netstandard]System.ArgumentException
		IL_006b: stloc.s 7

or in C#

	catch (object obj)
	{
		Exception ex = (Exception)obj;
		object obj2 = ex;
		if (!(obj2 is ArgumentException))
		{
			object obj3 = ex;
			if (!(obj3 is NotSupportedException))
			{
			// ... throw on exhaustion
			}
			NotSupportedException j = (NotSupportedException)(object)ex;
			NotSupportedException ex5 = j;
			bool store5 = store;
			NotSupportedException e4 = ex5;
			logException(store5, e4);
			return result;
		}
		ArgumentException a = (ArgumentException)(object)ex;
		ArgumentException ex6 = a;
		bool store6 = store;
		ArgumentException e5 = ex6;
		logException(store6, e5);
		return result;
	}

which discards the results of the isinst instructions, then does an unbox.any for any case that actually matches; which could provide a marginal space improvement, in the case where no clause matches -- i.e. another possible optimization the unhandled exception scenario; which in both cases are the "I don't care, this has just failed completely" route.

Friday, April 01, 2022

22Q1 Cycling

A milder winter than the last, with strong winds being the main feature; so a few longer rides early on, and storm-blown gaps in the record.

Late January snowdrops

January ended at 193.9 on the clock, or 116.1 miles for the month; February 314.2, meaning 120.3 miles for the month. March pushed the old bike to 611.1 on the clock (298.9 for the month including 2 off-meter), but the folder went to 78.5 (+11.9), and a new shopping bike clocked up 47.1, plus an unmetered 6.7 miles home for a total of 362.6 miles. Year to date, that's 601 miles, or about the same as last April.

Horse River Green

A burst of really warm weather near the end of the month allowed the first real exploration, rather than just pounding familiar nearby loops, this one exploring Cow Lane, from Linton to Great Chesterford, as a way of avoiding having to go as far as Saffron Walden to close the loop. Most of it is perfectly fine; but there's a section in the middle that suddenly went from dry to sodden, threading between ponds, and at times becoming indistinguishable from a river bed. Best for high summer, and from the Linton side, so the steep bit is downhill.

Saturday, January 01, 2022

Anime 2021

A generally disappointing year in all.

Spring season had a few "might watch" titles, but Crunchy picked up none of them, so I only picked up Odd Taxi, a noir-ish story of modern social-media driven ennui, which ends up being AOTY (long-form) pretty much by default.

Summer had the global release of Shin Eva, which was as much of a mess as it had seemed from original accounts, the painful and wildly mislabelled Fena, Pirate Princess (dropped after one episode of Fena being a vapid gold-digging whore), and Aquatope which began by looking like it would be cute girls doing cute aquarium things, with a little bit of low-key magic (from a local sprite wandering around in the first couple of episodes, and the occasional trippy underwater sequence), but rapidly turned into family drama and "welcome to the world of work", rather like Hanasaku Iroha, only without the bondage; and got dropped after 5 episodes.

Autumn brought just the tried and dropped Takt Op. Destiny, Sakugan and Digimon Ghost Game -- the latter being an episodic "urban legend kids' horror" series, a world away from Adventure, Adventure 02 and Adventure: that were a background to much of the year and now form an indistinguishable melange in my memory.

From the backlog, I went through Berserk in both '97 and '16 flavours, which passed some autumn evenings; but I still don't see what the fuss was about (except for the detailed crafting of the art in the original manga).

2H21 cycling

Ickneild Way, near Royston

In the second half of the year, I managed to do more each month than in 2020, reaching 2000 miles 21-Aug vs 29-Sep-20. At the end of November, I also managed to twist the frame on the old bike that had served me since '98, just shy of the 20,000 miles logged on that odo mark; and at the same time had odo problems on the newer bike, which just passed the 10,000 miles from new mark. Time to buy myself a present in the new year, I think.

As before, September was the high point -- monthly totals being July 361.1 (summer bike), August 504.4 (a little of the folding bike), September 609.9 (mostly summer bike) -- probably an all-time record -- October 429.1 (a dry month, this time, but mostly winter bike), November 309 miles (winter mostly, until written off), December 172 miles (including riding to both Christmas lunches I attended this year, much to the amazement of the others in the respective groups), for a total of just over 3700 miles for the year. The summer bike starts the new year with 77.8 miles on the (latest) clock, and the folding bike 66.5

While a lot of the rides were retreading old territory, I did a fair amount of exploration on byways, like taking the Ickneild Way most of the way from Royston to Baldock, even if many byways end up being just dead-ends; and from the ancient to the modern, making a lot of use of the new Girton to Fenstanton multi-use path in preference to the busway -- a very convenient fast route to places like the Golden Ball at Boxworth.

Henge, at Carriages, Fenstanton

The highlight of the year, though, was the opening of the long awaited Abbey Bridge, just before Christmas. Even if the Chisholm Trail itself is on the wrong side of the tracks for convenience (cycling it was only the second time in 40+ years living in the area that I'd taken the path across Coldhams Common), it means that I'll only use the Green Dragon bridge as and when I next visit the Green Dragon, which had been a regular location for pub lunch with former colleagues working on the Science Park, but alas such attendance has suffered under the continuing work-from-home regime.

Abbey Bridge, Christmas Eve, first full day of operation