Jump to content


  • Content Count

  • Joined

  • Last visited

About Eric

  • Rank

Profile Information

  • Gender
    Not Telling
  1. Eric

    using variants

    There is a simpler way that does not involve using asm and preserves typing to the last moment: using an anonymous class var Document external 'document' : Variant; ... procedure TForm1.W3Button5Click(Sender: TObject); begin ZoomCharts.TimeChart(class container = Document.getElementById("OBJ5"); area = class height : Integer = 663 // typing is optional but can be used if you don't want type inference end; data = class preloaded = class values : array [0..4] of array [0..1] of Integer = [ [0, 100], [1000, 200], [2000, 300], [3000, 400], [4000, 500] ]; &unit = 's'; end; timestampInSeconds = true; end; end); end; This will generate quite optimal JS. If you do not specify the field type, it will be inferred. If a field name is a reserved pascal name, like 'unit', you can use the usual escape by prefixing with '&'. If the field name contains non identifier characters, you can use external weirdFieldName = 'hello'; external 'weird@field.name'; You can also declare lambdas and functions in an anonymous class, sso JS code can pretty much be mapped 1:1 to Pascal by using Variant & Anonymous classes. The strong typing will still be there in expressions, can be explicited in field types, or by using more or less strict external classes. Depending on how well defined (or not) the external JS objects you are interfacing, it sometimes does not make much sense trying to strong type everything, because the calls parameters or optional objects are messy anyway. Also two quick notes: for creating a new empty JS object, the most efficient form is just "new JObject", for instance "v := new JObject" with v a Variant, the resulting JS is 'v = {}'. for an external class, the procedure only need the "external" qualifier if the JS name is different from the Pascal name, f.i. if you want TimeChart on the pascal side, while on the JS side it is "timeChart"
  2. Eric

    overload issue when 1st param is a string

    Unless I misunderstood the error is normal, since in case you have code with just a string parameter off(eventName); the compiler cannot figure out which of the overload is concerned. So you would need to specify that case separately and need 3 overloads: function off(eventName: string): JDom7; overload; function off(eventName: string; handler: TProcedure): JDom7; overload; function off(eventName: variant; delegatedTarget: variant; handler: TProcedure = nil): JDom7; overload;
  3. Eric

    Currency Data Type

    The main issue with supporting the Currency type is it really needs a 64 bit integer, and there are no 64 bit integers in JS, only floats and 32 bit integers. With 4 fixed decimals, a 32bit currency could thus only store amounts up to approx 200,000.0000 which is not much depending on the currency, and thus not really usable. The alternatives would be to either go for a float with systematic rounding, about 54 decimals of precision, not quite up to 64bit but probably good enough for all but the weakest currencies, or use a large integer library (might be slow however). If going for float, given the operations at risk are addition and subtraction, rather than an Integer-based Currency, the following could be enough for practical purposes (to be tested more) type Currency = Float; function AddCurrency(a, b : Currency) : Currency; begin Result := Round((a+*1000)*0.0001; end; function SubCurrency(a, b : Currency) : Currency; begin Result := Round((a-*1000)*0.0001; end; operator + (Currency, Currency) : Currency uses AddCurrency; operator - (Currency, Currency) : Currency uses SubCurrency; Limitations with the above is that you have to use FloatToStr(xxx, 4) to convert to string, or you might get some stray decimals. Bonus is that you can easily adjust the number of decimals for the "Currency" to the precision you need, which might go from zero for the Dong to 8 decimals for Bitcoin.
  4. Eric


    Yes, that is a current limitation I did not even think to test for (usually pack my strings in dedicated sections), I will add support for it in the next version. Otherwise resourcestring should works similarly to Delphi, though there is not yet anything in the IDE or RTL to facilitate them. All resource strings get an index are stored in a global JS-side array named "$R". Each time they are accessed, it is through a "$R[index]". So if you wish to switch language, you only have to change that $R array, either by re-assigning the variable to a a localized array in an asm section, or by replacing its items. In both cases gnu gettext can be leveraged quite directly.
  5. Eric

    Variant.AsBoolean always false

    It's the same behavior as in Delphi here: the variant will be cast on assignment. So in your snippet the Boolean cast will happen automatically for the "Result := vChecked;" line since Result is a Boolean. Also note that your code could be simplified to not involve any asm, just declare jQuery as an external function: function jQuery(v : Variant) : Variant; external '$'; ... function TjqxSwitchButton.GetChecked: Boolean; begin Result := jQuery('#' + TagId).jqxSwitchButton('checked'); end; Which takes advantages of the Variant method calls being resolved at runtime (same as in Delphi). The above method will be compiled to something like return ($("#"+TagId).jqxSwitchButton("checked")?true:false); With the 'jqxSwitchButton' call being transcribed verbatim, and the return value being cast to a Boolean automatically.
  6. Eric


    Would that class be defined in the implementation section of a unit rather than in the interface? If yes, then I think I know what's up.
  7. Eric

    Variant.AsBoolean always false

    Actually this is correct, Variants in Smart works similarly to Variants in Delphi (COM/OleVariant), ie. properties/methods you invoke on them as resolved "as they are" at runtime. In the case of Smart it means they're codegen'ed directly to JS. "vBool.AsBoolean" queries the AsBoolean property of your variant, in the case of a Boolean, there is no such property, so you get an "undefined", which is cast upon assignment to the bBool variable, resulting in a "false". If your vBool variant were to hold f.i { AsBoolean:"hello" } then vBool.AsVariant would return the "hello" string (and when cast to bBool, it would result in a "true"). There is a TVariant.AsBool() method which can perform the cast of a variant to a bool, but it's essentially legacy. Note that variants also support assignments of properties, f.i. var v : Variant := TVariant.CreateObject; // v contains {} v.AsBoolean := 'hello'; // v contains { "AsBoolean": "hello" } and it also works on arrays (ie. it's really similar to Variants in Delphi, as JavaScript objects are really similar to Variants)
  8. Eric

    IDE annoyances

    > as far as I know, there’s no case in which parentheses are allowed inside of the parens in a signature declaration Parenthesis can happen for expressions of default values of parameters, f.i: procedure Dummy(p : Integer = 3*(cWhatever + 5)); > If it does, look for “end.” at the end of the file Note that "end." is optional at the end of units, and there can be initialization/finalization sections.
  9. Eric

    Class methods on abstract classes

    "var a,b,c=0;" results in a & b left uninitialized at the "undefined" value. However do you have a particular snippet in mind?
  10. Eric

    Class methods on abstract classes

    I suspect the JS JITers don't have any (or much) support for typed arrays, so they just box the read/writes to typed arrays. There may be memory usage advantages, though I haven't done extensive testing in that area. However Chrome/FireFox which have the best Typed Arrays also already handle native arrays quite efficiently when all the elements are of the same type (which DWS enforces), as they use typed data with guard clauses. The internal typing is btw why the codegen always initializes variables with a typed value. This makes the JS code somewhat larger, but helps the JITters figure out the type of a variable earlier. And yes this is quite disappointing
  11. Eric

    Class methods on abstract classes

    Alas typed arrays performance is still not very good... I've been following them and monitoring from time to time, and at the moment, typed arrays are still not very convincing outside of the latest desktop browsers (Chrome & Firefox), though only in some scenarios. http://jsperf.com/native-vs-typed-js-array-speed/ (check the various revision of the above test case) That's still an improvement over the situation 6 months ago where they were slower everywhere, but having the compiler prefer typed array would still likely be detrimental (especially on mobile) Typed arrays are currently exposed through W3C.TypedArray if you want to test more specific scenarios.
  12. Eric

    How would I port this code?

    Delimiter for array constants is [], so MonthDays: array [boolean] of TDayTable = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]]; will work, the () was supported only for non-nested arrays (when the type is known). For the next version I version I extended the compiler so it will accept them for nested arrays as well when the type is fully qualified (as in your case). The reason behind using [] is to support array constants outside constant declarations, to initialize an array variable f.i, and also to allow type inference. The () constant array syntax is thus only supported for constant definitions, while [] is supported everywhere.
  13. Eric

    Referencing Pascal vars in asm block

    Currently only "immediate" references are allowed, ie. variables and fields. It should be possible to extend the support for simple (non-indexed) properties, but only in some cases, like property reads or functions calls. Property assignments on the other hand would be problematic, as they are function calls in disguise, so asm @AVar.Name = ‘hello’; end; would actually be equivalent to asm ClassOfSelf.SetName(@Self, 'hello'); end; if SetName is static (and something more complex if SetName is virtual, or if Self is an interface etc.) Also in the more general asm context, it's legal to have JS like asm var v = @AVar.Name = someFunc('hello'); end; which doesn't have any trivial output (as "someFunc" could have side effects, and so could "SetName"), so it would need to be fully parsed and recompiled, and so it would no longer be asm. The current approach is the have "asm" be as "hands off" as possible from a compiler POV. > should @Str.split(@ADelim) be legal? It will error if Str doesn't have a split field on the Delphi side, however (@Str).split(@ADelim) is allowed and safe.
  14. Eric

    Any plans for support of "with" keyword?

    A qualified "with" with a syntax identical to Oxygene is very likely to be added, as it's just syntax sugar for a type-inferenced, block-scoped local variable (which are already supported). The traditional "with" syntax is at the moment not planned for addition, as it leads to ambiguity, and AFAICT Embarcadero are moving away from it too. There may be refactoring tools out there that could help you refactor unqualified "with" away, but I'm not sure which (Castalia maybe?) As for the SmartPascal language, it's originally based on a "Delphi without 'with' and without pointers", but it incorporates multiple extensions & compatibility changes that allow it to also accept a variety of FreePascal & Oxygene syntax elements. It also has its own extensions which range from compatibility with JS/HTML to 1st-class dynamic arrays.
  15. Eric

    ? bug with MidStr() ?

    > What is the general philosophy of SMS regarding strings? Does it try to simulate pascal behavior Yes, SMS does use standard 1-based Pascal strings.