-
Content Count
70 -
Joined
-
Last visited
-
Days Won
2
Everything posted by pmcgee
-
@JohnLM ... (Throwing a possible small spanner) ... I'm not sure from the gif ... are you sorting the two lists?
-
One thing that is part of the challenge, from my perspective ... is when you can deal with Part 2 with only a reasonably small modification of your Part 1 solution. Maybe it's just me, but I find that very satisfying when it happens. 😎
-
I don't think you should be bothered about watermarks. In my favourite 'podcast with slides' of well over 100 episodes, the 'Activate Windows' logo has become an expected, even demanded, regular character.
-
function: how to return nil
pmcgee replied to jesu's topic in Algorithms, Data Structures and Class Design
@jesu I see this was a while back, but I'd encourage you to look up the idea of an Optional type. (One of) the points of an optional type, is that it doesn't reduce the value space of your inhabited type. Using 'NaN' or '-1' or whatever as a magic value might interfere with the validity of your use of the Double value. With an optional type , the inhabited type is uncontaminated by any other interpretation or usage. You can look at what it looks like in eg Spring4D, but here's the basic idea : type Maybe_Double = record // or Optional_Double ok : boolean; d : double; end; function Safe_Sqrt( i:integer ) : Maybe_Double; begin if i<0 then result.ok := false else begin result.ok := true; result.d := sqrt(i); end; end; begin for var i:= -2 to 2 do begin var ss := Safe_Sqrt(i); if ss.ok then writeln(i, ' ', d) else writeln(i, ' ','Undefined'); end; end. PS : Another feature of an optional type is that all uses of the inhabited type transfer into the "optional world". // If you have a function F( d:double ) : string, // then you can automatically have an 'identical' function OptF( od:maybe_double ) : maybe_string; begin if od.ok then exit( F(od) ) else exit( <the nil case> ) end; -
@JohnLM Great. This is perfectly reasonable .. for at least two reasons. 1) The challenge is about achieving a solution - dissecting the problem in a way that makes it solvable. 2) Eg in the day 2 and 3 problems, I put the data in Excel to manipulate it around, get a perspective on the contents, and to provide results to crosscheck against while I am only part way towards constructing my approach. I have kept them in my Github repo. 3) Also, some of the challenge is just reading in the data ... which can be sometimes tedious and/or obvious. I have used Excel and Notepad++ to make the data into a Delphi unit holding the info, when moving text with code was unrewarding. PS : There's a cool video from the guy that creates and runs the challenges from very recently. People solve the problems in many different ways - and not just with code. CppNorth - Keynote: Advent of Code, Behind the Scenes - Eric Wastl
-
Done. I've never used these before. 🙂
-
I'm lagging a little bit behind ... my solutions are here : https://github.com/pmcgee69/Advent-of-Code-2024/ My ultimate aim is to try to use a functional approach ... and to get ideas for better syntax for Delphi into the future. I'd really like to also solve in Rust and C++, for the learning but also for the ideas on syntax. I will definitely try to lean on eg Claude.io to work out solutions in those two. There's only so much time available!
-
A gem from the past (Goto)
pmcgee replied to Mike Torrettinni's topic in Algorithms, Data Structures and Class Design
Something I posted on the ADUG forum ... this C code (when I saw it) was posted on twitter as an amusing post about C. [ Cursed C code ] But after I'd thought about it for a bit, it occurred to me that maybe I could do the same in Delphi. And we can. 🙂 {$APPTYPE CONSOLE} program Project1; type range_struct = record type Tstate = (at_start, in_loop, done); var stop, step, i, start : integer; state : Tstate; function resume() : integer; constructor λ ( _start, _stop : integer; _step : integer = 1); end; constructor range_struct.λ( _start, _stop, _step:integer); begin start := _start; stop := _stop; step := _step; state := at_start; end; function range_struct.resume() : integer; label α,β,δ; begin case state of at_start : goto α; in_loop : goto β; done : goto δ; end; α : i:=start; repeat begin state := in_loop; exit(i); β : i := i + step; end until i >= stop; state := done; δ : exit(0); end; begin var ρ := range_struct.λ(1,20,2); var π := range_struct.λ(2,20,2); for var i in [1..5] do begin writeln('a ',i:2, 'th call : ', ρ.resume); writeln(' b ',i:2, 'th call : ', π.resume); end; writeln; writeln('Mwah ha ha. GOTO is back, baby!'); readln; end. That wasn't the original function-calling code that I had posted. It was only after a bit of mental digestion that I realised that this is (in my opinion) a really good, simplified, understandable model of a coroutine. ... and soon after I found out the original C code was part of an article commenting on c++ coroutines : https://probablydance.com/2021/10/31/c-coroutines-do-not-spark-joy/ -
Record operator overloading, can use undocumented return type
pmcgee replied to Khorkhe's topic in RTL and Delphi Object Pascal
It is, in a sense, a bit sad that the lack of user-definable infix operators leads to this sort of "creative interpretation". Shouldn't we complain about this almost as much as about 'With' eg ? This could have (should have?) been implemented by a JoinTo( s1, s2 : string) function. An actual Equality Operator should exhibit the qualities of being reflexive (a=a), symmetric (a=b => b=a), and transitive (a=b, b=c => a=c) (and going back to the first question ... it wouldn't need to return a boolean. Eg some cases, like a partial order, it might return an optional boolean)- 6 replies
-
- record
- operator-overloading
-
(and 1 more)
Tagged with:
-
D2007: Initialise byte array in const record
pmcgee replied to Nigel Thomas's topic in Algorithms, Data Structures and Class Design
^ I don't have D2007. Your D10+ version works in freepascal using {$mode delphi} and this works in fpc without it : sig2: FileSig = (Offset: 10; arrSig: ($00,$01,$02); ); -
Compile time issue with RTTI, generic interface and type casting...
pmcgee replied to Ali Dehban's topic in RTL and Delphi Object Pascal
@Ali Dehban can you expand on that ? I'm trying to picture why if you have an obj ( where the type = IMyInterface<xxx> ) anywhere in your code, you couldn't use obj.DoSomething . Isn't that the point of the interface? -
Compile time issue with RTTI, generic interface and type casting...
pmcgee replied to Ali Dehban's topic in RTL and Delphi Object Pascal
@Ali Dehban I like the idea of the area you were investigating here. Stretching my brain to a function that can return any type is something I have thought about in the last year or so. It took a while before I started to wrap my head around enough it to have questions, 'tho. The first was that IMyInterface<T> = interface function DoSomething: T; end; looks a lot like the definition of an anonymous function ... and then I replaced it with records. But I'll skip that for now. My second eventual question is why have function UseInterface<T> ( obj: IMyInterface<T> ) : T; begin Result := obj.DoSomething; end; vs just ? obj.DoSomething; So, as a first step I ended up with the following : (I realise you would have been simplifying the code above from your real use case) {$APPTYPE CONSOLE} program Project3; uses System.SysUtils, System.Variants, System.Classes, System.Rtti; type IWithAny<T> = interface function DoSomething: T; end; TWithAny<T> = class(TInterfacedObject, IWithAny<T>) function DoSomething : T; end; { TWithAny<T> } function TWithAny<T>.DoSomething: T; begin var val: TValue := TValue.Empty; var typ: T := default(T); case GetTypeKind(T) of tkString, tkUString : val := 'Hello'; tkInteger : val := 20; tkClass : if TValue.From<T>(typ).IsType<TStringList> then begin val := TStringList.Create; val.AsType<TStringList>.Add('Hello from StringList'); end; end; Result := Val.AsType<T>; end; var obj1 : IWithAny< Integer >; obj2 : IWithAny< String >; obj3 : IWithAny< TStringList >; begin obj1 := TWithAny< Integer > .Create; obj2 := TWithAny< String > .Create; obj3 := TWithAny< TStringList >.Create; writeln( obj1.DoSomething ); writeln( obj2.DoSomething ); var lvstr := obj3.DoSomething; writeln(lvstr.Text); lvstr.Free; readln; ReportMemoryLeaksOnShutdown := True; end. What I'd kinda like to see is the interface return a (managed record?) holding the <T>, made to clean up it's own memory. -
@EugeneK There is a short section in (at least) the Delphi 11 Alexandria version of Marco Cantu's Handbook (and probably earlier versions) called : Implementation of Anonymous Methods
-
Delphi should let me use a const array reference as a constant
pmcgee replied to PiedSoftware's topic in RTL and Delphi Object Pascal
That wouldn't be strange in C++ ... int i = 42; int main() { const int j = i; const int* p = &j; } -
Delphi 12.0 TParallel.For performance. Threading.pas issues
pmcgee replied to mitch.terpak's topic in General Help
Is it correct that each of your threads adds its own ThreadID to a main-thread Dictionary? Could there be any race issues there, or is access to it via some type of lock? -
The GetIt server is back online - With the 12.0 Patch 1
pmcgee replied to Lars Fosdal's topic in General Help
Is it running very quickly for everyone else as well, now? -
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
I just meant this type of situation where the C declarations are impenetrable, and Delphi is so much clearer: -
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
I have no problem with pointer to record ... I have been pretty scathing about C-style function declarations that are not broken down into more readable sub-types. We could separate ownership from access with something like : begin var o := TRecObject.Create; begin var p:PRec := @o.r; // use p for whatever end o.Free; end That pointer could be copied, passed to functions, whatever ... and simply pass out of scope. It wouldn't have ownership of the data object, and has no responsibility to release it. [edit - forgot] Or of course, you can have methods in the class to control and implement the access to the data object. I think this also highlights that the outer wrapper can be something other than manually managed. -
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
Yes. 100% I'm not arguing about it requiring management as is, ... or added structure to automate that. But of the code below, the new / dispose is (imo) ugly code that is unsuited to 2023, and to the long-term goal of regaining wider recognition of Delphi as a modern and relevant language. My standard rant / pedestal is that over the coming years we need to see Delphi improve it's language .. and it's practice ... to not be left behind by the general progress of other languages. Currently Delphi doesn't really qualify as a good teaching language any more - which I think is really sad. Without some more modern language facilities, it would be unfair to modern (say university level) students, and I'd like to see that change. begin var p:PRec := New(p); try p.x := 5; finally Dispose(p); end; end; begin var o := TRecObject.Create; try o.r.x := 5; finally o.Free; end; end -
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
Yes. I was arguing from a consistency and code-style view point. I don't agree. I don't think it is the generally accepted meaning of 'raw pointer'. Maybe you are thinking of 'void pointer' ? >> A raw pointer is a pointer whose lifetime isn't controlled by an encapsulating object, such as a smart pointer. A raw pointer can be assigned the address of another non-pointer variable, or it can be assigned a value of nullptr. Microsoft Learn - Raw Pointers -
Hi Ian. A nullable or option type basically adds a single possible "uninhabited" state to a return type of any kind. You can think of a function that can throw an exception in almost exactly the same way ... it has two possible states ... the normal return or the exception. I was operating on the assumption that the boolean you returned from your original function was indicating whether you successfully created a date range.
-
Not to be negatively critical, but can I suggest that there's a discussion to be had as to whether out parameters should be an out-dated usage style. @Ian Branch Can I take it that what you want returned from the function is EITHER a failure condition/error result OR a tuple of (startdate, enddate) ? If so, this is really a function with a single return type ... function GetWeekDates(const GivenDate: TDateTime; var SOWDay: string = 'SU') -> FAIL | (startdate, enddate) This could be known as a Nullable type, or Option type ... in Rust it is the Result type. When you return from this function, you either have (effectively) no result, or an inhabited tuple. There are quite a few published examples in Delphi of Nullable types .. .from Allen Bauer through to Spring4D. I'm not sure all of them capture the idea in the most functional way.
-
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
I would say, in probably every language, the recommendation should be to code in a way that is familiar and idiomatic for that language. If we wanted stack-allocation and hands-off memory safety, then we can use records .. even custom managed records. But if we want to use heap memory, then I think it only makes sense to do it in the same idiomatic language as all our other Delphi code. I don't think it's a wild opinion in 2023 that pretty much nobody outside of C code should be cooking up raw pointers. At least C++ has unique pointer and shared pointer. I guess we could cook up a smart pointer record to look after the heap-allocated memory ... that would still be avoiding raw pointers. In summary, I think the lesson from the C++ ecosystem is: pointers can be ok ... but {owning, raw} pointers are something to avoid. -
How can I force a record to be allocated on the heap ?
pmcgee replied to dormky's topic in Algorithms, Data Structures and Class Design
Wouldn't this be better expressed as a class containing a record? type TMyRec = record ... end; TMyRecC = class r : TMyRec; end; If C++ can declare "no raw pointers", then we certainly should avoid it in Delphi, right? This way you can maintain the usual convention with TMyRecC.Create and .Free, have constructor & destructor ... or use an interface ... or create your own smart pointer class ... -
Well. I learnt about something today. Recursive regexes.