Why we cannot declare local const variables in inno-setup [Code]? - constants

Do you know why when declaring local const vars, the script cannot compile?
Sorry, I know very little pascal and cannot figure out why this is not working!
This example (see function CircleArea) shows that my syntax should be fine.
http://www.tutorialspoint.com/pascal/pascal_quick_guide.htm
This is what I am trying to do:
//---placed within [Code]
procedure MyLog(const _functionName, _msg: String);
begin
Log(_functionName + '(): ' + _msg);
end;
function MyExec(const _filename, _params, _dir: String): Boolean;
const // <--- compilation fails in this line!
MethodName = 'MyExec';
var
ResultCode: Integer;
begin
MyLog(MethodName, _filename);
// ... invoke Exec(), etc. ...
end;
//---

You were trying that right. If Inno Setup were using Pascal it would even work, but since it is based on a custom Pascal Script language with limitation on declaring local constants, you can't do it that way. You must define your constant globally instead:
[Code]
const
MethodName = 'MyExec';
function MyExec(const _filename, _params, _dir: String): Boolean;
var
ResultCode: Integer;
begin
MyLog(MethodName, _filename);
// ... invoke Exec(), etc. ...
end;

You can use #define to define "local" constants and then use ExpandConstant('{#ConstantName}') whenever you need the value of that constant.
function MyExec(const _filename, _params, _dir: String): Boolean;
var
ResultCode: Integer;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
// ... invoke Exec(), etc. ...
end;
Note that the constant isn't actually local, because it is just a preprocessor definition. So the functions after MyExec could refer to the constant as well, which might be a potential cause of error (but isn't worse than defining a real global constant). You can redefine the same constant in another function or procedure without causing a compile error though.
function MyExec(const _filename, _params, _dir: String): Boolean;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;
function MyExec2(const _filename, _params, _dir: String): Boolean;
begin
// if you forget to put the next line, it will log 'MyExec'!!!
#define MethodName 'MyExec2'
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;
For added safety, you might want to #undef the "local" constant at the end of the function, in which case InnoSetup would cause a compile error if you'd try to reference it in the next function.
function MyExec(const _filename, _params, _dir: String): Boolean;
begin
#define MethodName 'MyExec'
MyLog(ExpandConstant('{#MethodName}'), _filename);
#undef MethodName
end;
function MyExec2(const _filename, _params, _dir: String): Boolean;
begin
// Forgot to define MethodName, but InnoSetup will cause an error
// "undeclared identifier: MethodName".
MyLog(ExpandConstant('{#MethodName}'), _filename);
end;

Related

Operator overloading for built-in data types and enums

Is overloading of implicit type conversion possible for enumerations in Delphi?
program TriState;
type
TTrilean = (trNone = -1, trFalse = 0, trTrue = 1);
TTrileanHelper = record helper for TTrilean
public
class operator Implicit(...)...; //E2123 PROCEDURE, FUNCTION, PROPERTY, or VAR expected
end;
var
v: TTrilean;
begin
v := trNone;
v := True; //Would like to have class operator Implicit here
end.
In the Delphi 10.4.2 documentation I read:
Note: Class and record helpers do not support operator overloading.

elixir metaprogramming for module attributes

I have this module
defmodule ElixirMeta.LangLoader do
#external_resource [Path.join([__DIR__, "es.json"]),
Path.join([__DIR__, "en.json"])]
defmacro __using__(_) do
for lang <- ["es", "en"] do
{:ok, body} = File.read(Path.join([__DIR__, "#{lang}.json"]))
{:ok, json} = Poison.decode(body)
quote do
def lang(unquote(lang)), do: unquote(Macro.escape(json))
end
end
end
end
defmodule ElixirMeta.Lang do
use ElixirMeta.LangLoader
end
I know I can define a function like:
def lang(unquote(lang)), do: unquote(Macro.escape(json))
And can be called like this:
Lang.lang("es")
Also even modify it's function name, like this:
def unquote(:"lang_#{lang}")(), do: unquote(Macro.escape(json))
And be called like this:
Lang.lang_es
But is it possible to do the same with a module attribute?
And being the module attribute compiled (?) I think is not possible to initialize it from the macro? maybe I would have to do it within before_compile macro?
I would like to access, for the purpose of the example, Lang.lang_es as a #lang_es and #lang_en LangLoader attributes
Yes, one can achieve that with Module.put_attribute/3 (I have created an MCVE out of your initial code):
defmodule ElixirMeta.LangLoader do
defmacro __using__(_) do
[
(quote do: Module.register_attribute __MODULE__,
:langs, accumulate: true) |
for lang <- ["es", "en"] do
quote do
def lang(unquote(lang)), do: unquote(lang)
Module.put_attribute __MODULE__,
:"lang_#{unquote(lang)}", unquote(lang)
Module.put_attribute __MODULE__,
:langs, unquote(lang)
end
end
]
end
end
defmodule ElixirMeta.Lang do
use ElixirMeta.LangLoader
def test do
IO.inspect {
#lang_es,
Enum.find(#langs, & &1 == "es"),
lang("es")
}, label: "Variants"
end
end
ElixirMeta.Lang.test
#⇒ Variants: {"es", "es", "es"}
The code above declares the accumulated attribute (#attr :foo followed by #attr :bar would produce [:foo, :bar] value instead of overwriting the attribute value, single attribute and the function.
Please note, that there is no way to access module attribute from outside, since module attributes are compile-time entities.

why = is optional in def in Scala

Both of the following function definations compile even though one uses = and other doesn't. Why? Is there an advantage of this behaviour?
def 1
def doWork(index:Int) = {
sleep((math.random*1000).toLong);
index;
}
def 2
def doWork(index:Int) {
sleep((math.random*1000).toLong);
index;
}
def 1 is what you want to use.
def 2 is called procedure syntax (discouraged) and actually means this:
def doWork(index:Int): Unit = {
sleep((math.random*1000).toLong)
index
}
So it's probably now what you want (since it doesn't return anything).
Not including an = sign declares a procedure. Procedures return Unit, i.e., don't return a value at all. As explained in the Scala language specification (from the link above):
A procedure definition is a function definition where the result type and the equals sign are omitted; its defining expression must be a block. E.g., def f(ps) {stats} is equivalent to def f(ps): Unit = {stats}.
In your second case, the return value simply gets suppressed to turn a function that returns Int into a procedure that returns Unit. While doing so, the compiler should issue a warning similar to
warning: a pure expression does nothing in a statement position
This should let you know that something fishy is going on, i.e., there is a statement that would normally result in the block returning a value (index; in your case), but it goes unused.
When you don't use "=" with def, it means your defined function will return unit.
And in the second function, you don't use "=", that means the defined function will return unit, but your function is returning index.
That's why it throws warning as it expects unit and discard the value.
Thanks

Ada Compiler abandons Instantiation of package passing overloaded operators

I want to instantiate a package and pass functions to it that overload operators in order to make a Generic Binary Search Tree. Here's the specifications.
bstgen.ads (snippet)
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation;
GENERIC
type Akey is private;
type TreeRecord is private;
with function "<"(K: in Akey; R: in TreeRecord) return Boolean;
with function ">"(K: in Akey; R: in TreeRecord) return Boolean;
with function "="(K: in Akey; R: in TreeRecord) return Boolean;
PACKAGE BSTGen IS
TYPE St10 IS NEW String(1..10);
TYPE TreePt IS PRIVATE;
PACKAGE EnumIO IS NEW Ada.Text_IO.Enumeration_IO(Akey); USE EnumIO;
driver.adb (snippet)
with Ada.Text_IO; use Ada.Text_IO;
WITH BSTGen;
PROCEDURE Driver IS
IP: Integer := 1;
TYPE Names IS (Resig,Keene,Marsden,Vuijic,Marcus,Gonzalez);
PACKAGE NamesIO IS NEW Ada.Text_IO.Enumeration_IO(Names);
type St10 is NEW String(1..10);
type Customer is
record Name: Names;
PhoneNumber: St10;
end record;
function "<"(K: in Names; R: in Customer) return Boolean is begin
return K < R.Name;
end "<";
function ">"(K: in Names; R: in Customer) return Boolean is begin
return K > R.Name;
end ">";
function "="(K: in Names; R: in Customer) return Boolean is begin
return K = R.Name;
end "=";
PACKAGE IntIO IS NEW Ada.Text_IO.Integer_IO(Integer); USE IntIO;
PACKAGE mybst is NEW BSTGen(Names,Customer,<,>,=); USE mybst;
R, Pt: TreePt;
Name: Names;
Phone: St10;
Status: Boolean;
BEGIN
R := CreateTree;
Pt := R;
However, when I try to compile, this is the output:
driver.adb:24:04: expect subprogram or entry name in instantiation of "<"
driver.adb:24:04: instantiation abandoned
bstgen.ads:19:53: expect discrete type in instantiation of "Enum"
bstgen.ads:19:53: instantiation abandoned
This includes a bunch of errors stating that driver.adb's methods are not visible, which is to be expected as the instantiation of mybst is abandoned. How do I fix this?
In bstgen.ads, you say
PACKAGE EnumIO IS NEW Ada.Text_IO.Enumeration_IO(Akey);
but in the generic formal part you said
type Akey is private;
which means that the compiler can assume very little about the actual type except that equality and assignment are available. It could be a record of hundreds of bytes; it certainly need not be an enumeration.
To ensure that Akey is an enumeration, you need to say
type Akey is (<>);
as in ARM12.5(13).
In driver.adb, you say
PACKAGE mybst is NEW BSTGen(Names,Customer,<,>,=);
which should read
PACKAGE mybst is NEW BSTGen(Names,Customer,”<“,”>”,”=“);

Pascal: Interfaced Class, to Double, to Interface instance

This is a bit of an extension on another of my questions. I've got a DLL that is supposed to interface with Game Maker, which uses Double and PChar.
I have to convert my objects to Doubles (references) to pass back and forth with Game Maker.
I have 2 Classes: TBitmap and TWindow. Each implements IBlittable. This means that methods operating on IBlittables can use both, however here's the problem:
Here's how I create them:
{Creation of Bitmaps and Windows}
function CreateBitmap(W, H: Double): Double; STDCall;
var
TBM: TBitmap;
begin
TBM := TBitmap.Create(Floor(W), Floor(H));
CreateBitmap := Double(Integer(TBM));
end;
function GetWindowByHWND(Handle: Double): Double; STDCall;
var
ReturnVal: TWindow;
begin
ReturnVal := TWindow.Create(Floor(Handle));
GetWindowByHWND := Double(Integer(ReturnVal));
end;
And here's how I am trying to operate on them:
function SetPixel(Handle, X, Y, Color: Double): Double; STDCall;
var
<stuff>
begin
Blittable := IBlittable(Floor(Handle)); //This!
<set the pixel>
SetPixel := 0;
end;
When I cast the Floor(Handle) to IBlittable, it segfaults and crashes.
When I cast it to what it previously was (a TWindow or a TBitmap) it works fine. How do I circumvent this problem?
I really don't want to rewrite all the methods specifically (that'd be pretty redundant and lame)
I needed to change the types in the creation functions:
function CreateBitmap(W, H: Double): Double; STDCall;
var
TBM: IBlittable; //See
begin
TBM := TBitmap.Create(Floor(W), Floor(H));
CreateBitmap := Double(Integer(TBM));
end;
function GetWindowByHWND(Handle: Double): Double; STDCall;
var
ReturnVal: IBlittable; //Here too
begin
ReturnVal := TWindow.Create(Floor(Handle));
GetWindowByHWND := Double(Integer(ReturnVal));
end;