czw., 1 gru 2022 o 23:16 Per Bothner napisaƂ(a): > > > On 12/1/22 03:19, Panicz Maciej Godek via Kawa wrote: > > I've been trying to build a simple wrapper for a hash table, > > that I call Bundle, such that > > > > (Bundle x: 5 y: 10) > > > > would return a bundle object, let's call it b, so that I could refer to > its > > fields using > > > > b:x > > That would be a nicer syntax, but there could be some problems combining > the concepts of hash-table (extensible with arbitrary keys, not > necessarily strings) > and structures (with a fixed set of keys). JavaScript does it, and it > does make > things more convenient. > > There are a lot of issues to consider. Should key names be strings or > symbols? > What about keys that are not names (keys or strings)? I think they have to be Strings, because of how the HasNamedPart interface is defined. > How does this conflict > with existing usage of colon-notation, and how do we deal with those? > > So I'm not sure if hash tables should implement HasNamedParts by default. > > No, I don't think so either. But I think it would be nice if Kawa facilitated adding such classes. For the development of GRASP, I have built a macro called define-type , which is used for defining record-like classes. It is used like this: (define-type (Extent width: real height: real)) And it defines a class that can be instantiated as (define e ::Extent (Extent width: 10 height: 20)) I also have a pattern matcher which supports this notation, so I can write things like (match e ((Extent width: size height: size) 'square) ((Position width: w height: h) 'rectangle)) I like it way more than any SRFI record proposals I've seen. Also, with Kawa's syntax extensions I can write (set! e:width 50) and it Just Works. I find this experience very satisfying (to be honest, I'm quite surprised that many modern languages like Java or Haskell have much worse capabilities of defining structures than the C language). And I thought it would be nice to have a more flexible record-like type that I call Bundle (referring to David Hume's "bundle theory of meaning") -- so that it would also work in the context of pattern matching etc. I don't expect it to be the main interface to hash tables. An alternative is to use function-call notation, like we do for vectors: > (TABLE KEY) > (set! (TABLE KEY) VALUE) > This has the advantage that it does't conflict with other uses of > colon-notation. > However, it doesn't provide a constructor syntax "for free". > > Yes, I actually use that a lot in GRASP. I have defined a bunch of macros such as define-mapping (which uses a normal hash table underneath) or define-property (which uses a weak-key table) that is used like this: (define-property (dotted? cell::cons)::boolean #f) The nice thing about this is that it lets me provide the default value very naturally (and I could also signal error for missing keys). I also have a variant of weak-key which can accept more than one argument, that is called define-cache (and it's achieved by means of "currying", i.e. constructing hash tables that return hash tables etc.) But the difference between those hash tables and bundles is that bundles are meant to be externalizable, whereas properties are essentially opaque. I brought up these concerns on the mailing list years ago. If someone can > find these old message it might be helpful ... > > > I have found that Kawa offers a gnu.mapping.HasNamedParts interface which > > facilitates value reference, ...s > > The source code for the gnu.kawa.functions.SetNamedPart.apply3 method > > reveals, that there was a plan for supporting this -- the method begins > > with a commented-out fragment: > > > > /* > > if (container implements HasNamedParts) > > return ((HasNamedParts) container).getNamedPart(part); > > */ > > > > which wouldn't work with current Kawa, because the HasNamedParts > interface > > doesn't containt getNamedPart method, and instead it contains a method > > called get. I think that this could be fixed by: > > - adding a method Object set(String key, Object value) to the > HasNamedParts > > interface > > - uncommenting and fixing the above snippet to invoke the above method. > > That is probably OK, except use 'put' instead of 'set' to be consistent > with java.util.Map. > Also, 'put' needs a default implementation, which should probably > throw UnsupportedOperationException. (Defaults were added in Java 8. It > is probably > OK to require Java 8 as a minimum at this point - though Android might be > an issue.) > > Actually Android SDK ships with a tool called d8, which is a replacement for their dx converter, which handles the Java 8 bytecode (I was even able to generate byte code for API level 1 with it) > Do compare with the getNamedPart and apply 2 method in GetNamedPart. > They handles various extra cases, that might not be appropriate for a > setter. > > > By the way, the interface also contains isConstant method, which doesn't > > seem to be documented anywhere. > > isConstant(KEY) returns true is the binding for KEY is immutable. > It is used to optimize namespace resolution. > > I think that also - for consistency - the > > interface should also provide a boolean hasPartNamed(String name) method. > > > > But this only solves one problem, and there's another one, namely - when > I > > try to initialize Bundle as, say > > > > (Bundle x: 5 y: 10) > > > > I get the following warnings: > > > > /dev/tty:6:20: warning - no field or setter 'x' in class Bundle > > /dev/tty:6:20: warning - no field or setter 'y' in class Bundle > > > > These are issued from the build() method in > > gnu.kawa.reflect.CompileBuildObject. It does seem that this class doesn't > > take into account the existence of the HasNamedParts interface at all. > > That is probably the case. > > > Is there any way out of this situation? > > If there was a clean problem-free solution I would have already done so ... > That doesn't mean we shouldn't have a better syntax for hash-tables, > or that this is a dead end - but there are definitely a number of issues > to consider. > > Again, I don't want to push for having an opinionated way of dealing with hash tables. I think it would be sufficient if Kawa could provide their users (or me in particular :D) with the means of creating various different solutions and experimenting with them. I think that supporting setters for HasNamedPart and in CompileBuildObject would simply be consistent with the idea of the HasNamedPart interface, and it doesn't seem to break anything